戰(zhàn):用 `@rrweb/rrweb-plugin-sequential-id-record` 為錄制事件打上連續(xù)編號(hào))
rrweb 事件順序 ID 插件實(shí)戰(zhàn)用rrweb/rrweb-plugin-sequential-id-record為錄制事件打上連續(xù)編號(hào)【免費(fèi)下載鏈接】rrwebrecord and replay the web項(xiàng)目地址: https://gitcode.com/gh_mirrors/rr/rrweb本文介紹 rrweb 官方插件rrweb/rrweb-plugin-sequential-id-record順序 ID 錄制插件的安裝、配置與底層原理。它通過(guò)與rrweb/rrweb-plugin-sequential-id-replay配合使用為錄制階段產(chǎn)出的每一個(gè)事件附加一個(gè)從 1 開(kāi)始遞增的序號(hào)并在回放階段校驗(yàn)事件順序是否完整、是否發(fā)生丟幀或亂序。讀完本文你將掌握如何為事件流添加穩(wěn)定的順序標(biāo)識(shí)、如何在回放端做一致性校驗(yàn)以及該機(jī)制在事件關(guān)聯(lián)與調(diào)試中的典型用法。插件定位與回放端插件成對(duì)使用rrweb 的錄制與回放默認(rèn)依賴事件內(nèi)的timestamp來(lái)排序與驅(qū)動(dòng)時(shí)間軸但時(shí)間戳并非嚴(yán)格單調(diào)且無(wú)法直接表達(dá)“事件流中第 N 個(gè)事件”這一語(yǔ)義。順序 ID 插件正是為解決這一問(wèn)題而生錄制端本文主角在每個(gè)事件被 emit 之前往事件對(duì)象上寫(xiě)入一個(gè)全局遞增的整數(shù) ID回放端讀取該 ID檢查事件到達(dá)順序是否為 1、2、3…… 的連續(xù)遞增序列一旦發(fā)現(xiàn)跳躍、重復(fù)或缺失立即在控制臺(tái)輸出錯(cuò)誤信息。官方文檔明確要求兩個(gè)插件“成對(duì)使用”詳見(jiàn) rrweb/rrweb-plugin-sequential-id-replay 的 README。完整的 rrweb 使用說(shuō)明見(jiàn)倉(cāng)庫(kù)根目錄的 guide.md插件的通用機(jī)制RecordPlugin/ReplayPlugin接口見(jiàn) 插件 API 文檔。安裝與 rrweb 其它插件一樣通過(guò) npm 安裝即可npm install rrweb/rrweb-plugin-sequential-id-record從 package.json 可以看到該包要求rrweb ^2.1.1作為 peerDependency同時(shí)聲明了 UMDmain/unpkg/jsdelivr與 ESMmodule兩種產(chǎn)物因此既適合打包器內(nèi)的import使用也適合 CDN 直接引入。配套的回放插件需要單獨(dú)安裝npm install rrweb/rrweb-plugin-sequential-id-replay基本用法在 record 配置中掛載插件在錄制端通過(guò)record的plugins配置項(xiàng)將插件注入事件處理管線import { record } from rrweb/record; import { getRecordSequentialIdPlugin } from rrweb/rrweb-plugin-sequential-id-record; record({ emit: function emit(event) { // 將事件發(fā)送到服務(wù)端 }, plugins: [ getRecordSequentialIdPlugin({ key: _sid, // 默認(rèn)值 }), ], });要點(diǎn)說(shuō)明record的plugins選項(xiàng)在 guide.md 中有官方定義默認(rèn)值為[]用于“l(fā)oad plugins to provide extended record functions”getRecordSequentialIdPlugin是工廠函數(shù)調(diào)用后返回一個(gè)RecordPlugin實(shí)例示例中的key參數(shù)可以省略因?yàn)開(kāi)sid就是它的默認(rèn)值。生成的插件名與事件形態(tài)插件內(nèi)部聲明了固定的插件名常量PLUGIN_NAME rrweb/sequential-id1見(jiàn) src/index.ts。插件本身不產(chǎn)生EventType.Plugin類型的獨(dú)立事件而是通過(guò)eventProcessor對(duì)每一個(gè)即將 emit 的事件原地改寫(xiě)向事件對(duì)象上寫(xiě)入{ [_options.key]: id }id 從 1 開(kāi)始、每次自增。因此一個(gè)典型事件的最終形態(tài)類似于{ type: 3, // IncrementalSnapshot timestamp: 1690000000000, data: { /* ...原始增量數(shù)據(jù)... */ }, _sid: 42, // 插件寫(xiě)入的順序 ID }由于eventProcessor對(duì)所有類型的事件FullSnapshot、Meta、IncrementalSnapshot、Custom 等統(tǒng)一生效因此整條事件流中的每個(gè)事件都能拿到唯一的順序編號(hào)。源碼級(jí)原理eventProcessor 注入鏈要理解該插件為什么能“給所有事件加 ID”需要看 rrweb 錄制端的事件處理管線。record/index.ts 中定義了內(nèi)部eventProcessorconst eventProcessor (e: eventWithTime): T { for (const plugin of plugins || []) { if (plugin.eventProcessor) { e plugin.eventProcessor(e); } } // ...packFn 等后續(xù)處理 return e; };所有事件在 emit 之前都會(huì)依次經(jīng)過(guò)每個(gè)插件注冊(cè)的eventProcessorRecordPlugin接口定義在 packages/types/src/index.ts 的RecordPlugin類型中。順序 ID 插件正是利用這一點(diǎn)在eventProcessor回調(diào)里執(zhí)行Object.assign(event, { [_options.key]: id })實(shí)現(xiàn)零侵入地為事件流注入連續(xù)編號(hào)。值得注意的實(shí)現(xiàn)細(xì)節(jié)工廠函數(shù)內(nèi)部用Object.assign({}, defaultOptions, options)合并默認(rèn)值因此傳入{ key: myId }時(shí)只會(huì)覆蓋key其它默認(rèn)行為不受影響計(jì)數(shù)器id是工廠函數(shù)閉包內(nèi)的局部變量隨插件實(shí)例創(chuàng)建而復(fù)位為 0——這意味著每次調(diào)用record()開(kāi)啟新的錄制會(huì)話時(shí)順序 ID 都會(huì)從 1 重新開(kāi)始同一會(huì)話內(nèi)才保證單調(diào)遞增插件名rrweb/sequential-id1中的版本號(hào)后綴1遵循 rrweb 插件命名約定便于未來(lái)以帶版本的方式兼容演進(jìn)?;胤哦伺涮仔r?yàn)順序一致性的守門(mén)員錄制端負(fù)責(zé)“打 ID”回放端則負(fù)責(zé)“查 ID”。配套插件rrweb/rrweb-plugin-sequential-id-replay的使用方式如下其完整 README 見(jiàn) packages/plugins/rrweb-plugin-sequential-id-replay/README.mdimport { Replayer } from rrweb/replay; import { getReplaySequentialIdPlugin } from rrweb/rrweb-plugin-sequential-id-replay; const replayer new Replayer(events, { plugins: [ getReplaySequentialIdPlugin({ // 必須與錄制端保持一致 key: _sid, // 默認(rèn)值 warnOnMissingId: true, // 默認(rèn)值 }), ], }); replayer.play(); // ERROR: [sequential-id-plugin]: expect to get an id with value 42, but got 666回放端插件的行為邏輯見(jiàn) rrweb-plugin-sequential-id-replay/src/index.ts維護(hù)一個(gè)內(nèi)部計(jì)數(shù)器currentId初始值為 1對(duì)每個(gè)事件先檢查key是否存在于事件上存在比較事件攜帶的 ID 與期望值currentId。相等則currentId不相等則輸出console.error錯(cuò)誤格式為[sequential-id-plugin]: expect to get an id with value 期望值, but got 實(shí)際值——這正是官方示例中replayer.play()后出現(xiàn)的報(bào)錯(cuò)來(lái)源不存在若warnOnMissingId為true默認(rèn)值輸出console.warn[sequential-id-plugin]: failed to get id in key: key?;胤哦瞬寮峭ㄟ^(guò)ReplayPlugin的handler掛載到事件回放流程中的handler的調(diào)用點(diǎn)位于 replay/index.ts 中CAST_EVENT狀態(tài)機(jī)投遞事件之前。也就是說(shuō)校驗(yàn)發(fā)生在事件被真正應(yīng)用到 DOM 之前一旦 ID 序列斷裂能第一時(shí)間在控制臺(tái)暴露問(wèn)題。配置參數(shù)一覽參數(shù)默認(rèn)值插件端說(shuō)明key_sid錄制端 回放端事件上存放順序 ID 的字段名兩端必須一致warnOnMissingIdtrue僅回放端事件上找不到key字段時(shí)是否輸出警告關(guān)于默認(rèn)值的補(bǔ)充說(shuō)明錄制端默認(rèn)key為_(kāi)sid見(jiàn) record 插件源碼 中defaultOptions回放端默認(rèn)key同樣為_(kāi)sid見(jiàn) replay 插件源碼 中defaultOptions。在配置時(shí)強(qiáng)烈建議顯式指定與錄制端完全相同的key值避免因文檔示例與默認(rèn)值不一致造成兩端錯(cuò)位例如錄制端寫(xiě)入了_sid回放端卻在讀_id結(jié)果每個(gè)事件都觸發(fā)failed to get id in key的警告。典型應(yīng)用場(chǎng)景從插件的能力邊界出發(fā)它適合以下場(chǎng)景事件與業(yè)務(wù)日志的精確關(guān)聯(lián)當(dāng)事件經(jīng)由服務(wù)端存儲(chǔ)、再按需拉取回放時(shí)可借助順序 ID 把回放中的每一個(gè)事件與后端日志、錯(cuò)誤堆棧、埋點(diǎn)數(shù)據(jù)一一對(duì)上號(hào)定位“回放到第幾步出問(wèn)題”回放完整性與丟幀檢測(cè)事件在傳輸、壓縮或存儲(chǔ)過(guò)程中若發(fā)生缺失/亂序例如 WebSocket 斷線重連、事件分批落庫(kù)后再合并回放端插件的連續(xù)性校驗(yàn)會(huì)立即報(bào)錯(cuò)幫助你發(fā)現(xiàn)數(shù)據(jù)管道的問(wèn)題調(diào)試錄制鏈路在開(kāi)發(fā)自定義插件或修改事件流時(shí)順序 ID 提供了一種低成本的事件計(jì)數(shù)手段可以快速確認(rèn)每個(gè)事件是否都經(jīng)過(guò)了預(yù)期的處理管線。需要說(shuō)明的是該插件只負(fù)責(zé)“編號(hào) 校驗(yàn)”不參與事件的時(shí)間軸調(diào)度——回放推進(jìn)仍由timestamp驅(qū)動(dòng)順序 ID 更多承擔(dān)的是調(diào)試與一致性保障職責(zé)。若需深入了解 rrweb 事件模型與插件開(kāi)發(fā)可繼續(xù)閱讀 事件機(jī)制文檔、插件 API 文檔 以及倉(cāng)庫(kù)根目錄的 guide.md?!久赓M(fèi)下載鏈接】rrwebrecord and replay the web項(xiàng)目地址: https://gitcode.com/gh_mirrors/rr/rrweb創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考