最近在作 web 端錄製 和回放的時候遇到一個比較好的庫 rrweb, 可是網上的資料相對比較少,擼了遍源碼,作個小總結。本文閱讀大概會了解到如下幾個方面~node
rrweb 是什麼git
適用場景github
錄製回放實現原理web
使用 rrweb 應注意的問題數組
安全問題安全
rrweb 庫組成部分 + 簡介服務器
rrweb 各個模塊對應的技術細節數據結構
web 端錄製回放的一個基礎庫,即記錄頁面中的 DOM 結構還有用戶操做行爲,在遠程實現回放。一圖勝千言,可看下面的gif 圖 app
這一塊能夠簡單地理解爲 「快照 + 操做指令」, 通常記錄頁面狀態,咱們能夠根據時間記錄每一時刻頁面的 DOM狀態,回放的時候根據時間點顯示便可,可是通常一個頁面DOM 數據是很龐大的,以下圖所示,這個仍是頁面 DOM 比較少的狀況 異步
所以 rrweb 採起了另一種方式,記錄初始頁面的DOM 狀態,或者特定某個時刻的DOM 狀態,後續收集的是不一樣時間點的操做指令 或者 某個時刻 某個DOM 的變化做爲一個增量快照,在原先快照的基礎上,不斷加入根據行爲解析的DOM 數據,構建了後續的快照,減小大量數據的存儲或傳輸。
除此之外,可本身對收集到的數據進行處理
關於數據安全問題,這個應該加密便可
一、rrweb-snapshot 提供了 snapshot, resbuid接口,snapshot遍歷 頁面DOM 返回當前頁面 DOM 視圖的一個序列化的數據結構, rebuild, 則解析特定的數據還原DOM, 並插入文檔中 例如:
這個模塊的功能主要有: a) snapshot 方法
第一點:Snapshot 經過 takeFullSnapShotg構建頁面 DOM 樹,同時生成了 id -> Node 的映射,即在構建 DOM 樹時爲每一個節點生成一個惟一的id, 同時根據 id 生成一份映射,這個映射只要是爲了方便後續的增量快照操做
第二點: 將href,src,CSS中的相對路徑設爲絕對路徑 將一些腳本,樣式,圖片等引用的相對路徑改成絕對路徑 好比:
那通過轉換以後,回放時,圖片的連接地址已經變爲以前域名下的地址
第三點: 將頁面引用的樣式變爲內聯樣式,以確保可使用本地樣式 將頁面引用的樣式讀取變爲內聯樣,例如
除此之外,還有一種樣式邏輯,即經過 CssStyleSheet.sheet.insertRule的形式插入頁面的樣式:
第四點:將一些DOM狀態內聯到HTML屬性中,例如HTMLInputElement的值
記錄沒有反映在 HTML 中的視圖狀態。例如 輸⼊後的值不會反映在其 HTML中,咱們須要讀取其 value 值並加以記錄
第五點:將script標記轉換爲noscript標記,以免腳本被執行 在播放錄製頁面時,頁面的腳本是不可以被執行的,須要禁掉
b) rebuild方法 經過建立Dom, 設置屬性等,而且將對應的DOM 插入文檔中
二、Rrweb 提供了 record 和 replay 功能。 a) record 方法: 前面說到增量快照,那增量數據是怎麼收集的呢?開始錄製以後,會針對當前頁面生成一個DOM 快照,而後開始監聽用戶操做和頁面DOM的變化。 監聽行爲以下:
監聽的方式有: (1)MutationObserver 其中,監聽 DOM 變化 主要是經過 API --- MutationObserver 來實現。當監視的DOM 發生變更時, MutationObserver 將收到通知並觸發預先設定好的回調參數,與 addEventListener 方法 比較類似 例如:
如上圖所示,當咱們嘗試改變頁面 DOM 的屬性,或者新增 DOM 節點的時候,都會對應生成一條 MutationObserver record, record 記錄了一些變更信息~ 在 rrweb 中, 對每一條mutation record 作了幾下處理
針對不一樣的類型進行處理, characterData 是節點內容或節點文本變更,attributes 是節點屬性的變更,childList 是子節點的變更,包括新增子節點,移除子節點,移動子節點等。
新增節點的邏輯 在初始記錄時,生成了頁面快照同時維護一個 id -> Node 的映射, 所以當出現新增節點時,無需從新完整地生成一份快照,而只須要將新節點序列化並加入映射中便可。 因爲MutationObserver觸發方式爲批量異步回調,具體來講就是會在一系列 DOM 變化發生以後將這些變化一次性回調,傳出的是一個 mutation 記錄數組,那在序列化的時候,會存在重複記錄的問題 例如如下例子中
如下兩種方式均可以生成這種DOM 結構
一、建立節點 n1 並 append 在 body 中,再建立節點 n2 並 append 在 n1 中。 二、建立節點 n一、n2,將 n2 append 在 n1 中,再將 n1 append 在 body 中。
MutationObserver 對這兩種Dom 操做方式的輸出記以下圖所示
第一種方式 record 記錄
這種狀況下雖然 n1 append 時尚未子節點,可是因爲上述的批量異步回調機制,當咱們處理 mutation 記錄時獲取到的 n1 是已經有子節點 n2 的狀態
第二種方式 record 記錄
在處理序列化的過程當中,在處理新增節點時必須遍歷其全部子孫節點,才能保證全部新增節點都被記錄,可是這一策略應用在第一種狀況中就會致使 n2 被做爲新增節點記錄兩次,回放時就會產生與原頁面不一致的 DOM 結構,所以,爲避免這種狀況, rrweb 中採起了‘惰性’新增節點,即在遍歷 mutation record 時,不會立馬去序列化新增的節點,而是收集新增的節點,在遍歷完mutation 全部記錄的時候再統一去重,序列化新增節點。
刪除節點的邏輯
(2)鼠標移動,鼠標交互,頁面滾動,視窗大小這些則經過 事件綁定的形式去監聽,以下面頁面滾動的監聽
on 方法也是經過 addEventListener 的形式監聽
b) replay 解析收集到的events 集合,進行還原 收集到的事件類型有
第一次閱讀源碼,寫分析,可能比較粗糙,如有錯誤之處,歡迎指正。也歡迎一塊兒交流,相關的問題也能夠到github 上向做者提問哦,做者響應問題速度也是挺快的。