什麼是雙緩衝?

以 canvas 爲例子,當我們用 canvas 繪製動畫,每一幀繪製前都會調用 ctx.clearRect 清除上一幀的畫面。

如果當前幀畫面計算量比較大,我們就很容易因爲繪製太慢了出現白屏。爲了解決這個問題,我們可以先在內存中繪製當前幀的動畫,繪製完畢後,直接用當前幀替換上一幀,這樣就省去了兩幀的替換時間,不會出現從白屏到出現畫面的閃爍情況。這種在內存中構建並直接替換的技術叫做雙緩衝。

React 使用 “雙緩存” 來完成 Fiber 樹的構建與替換——對應着 DOM 樹的創建與更新。

react 根據雙緩衝機制維護了兩個 fiber 樹,一顆用於渲染頁面 (current),一顆是 workInProgress Fiber 樹,用於在內存中構建,然後方便在構建完成後直接昔換 current Fiber 樹。

workInprogress Fiber 樹的 alternate 指向 Current Fiber 樹的對應節點, current 表示頁面正在使用的 fiber 樹。

當 workInprogress Fiber 樹構建完成,workInProgress Fiber 則成爲了 current 渲染到頁面上,而之前的 current 則緩存起來成爲下一次的 workInProgress Fiber,完成雙緩衝模型。

首先要明白,React 要完成一次更新分爲兩個階段:render 階段和 commit 階段,兩個階段的工作可分別概括爲新 fiber 樹的構建和更新最終效果的應用。

render 階段

render 階段實際上是在內存中構建一棵新的 fiber 樹(稱爲 workInProgress 樹),構建過程是依照現有 fiber 樹(current 樹)從 root 開始深度優先遍歷再回溯到 root 的過程,這個過程中每個 fiber 節點都會經歷兩個階段:beginWork 和 completeWork。組件的狀態計算、diff 的操作以及 render 函數的執行,發生在 beginWork 階段,effect 鏈表的收集、被跳過的優先級的收集,發生在 completeWork 階段。構建 workInProgress 樹的過程中會有一個 workInProgress 的指針記錄下當前構建到哪個 fiber 節點,這是 React 更新任務可恢復的重要原因之一。

commit 階段

在 render 階段結束後,會進入 commit 階段,該階段不可中斷,主要是去依據 workInProgress 樹中有變化的那些節點(render 階段的 completeWork 過程收集到的 effect 鏈表), 去完成 DOM 操作,將更新應用到頁面上,除此之外,還會異步調度 useEffect 以及同步執行 useLayoutEffect。

這兩個階段都是獨立的 React 任務,最後會進入 Scheduler 被調度。render 階段採取的調度優先級是依據本次更新的優先級來決定的,以便高優先級任務的介入可以打斷低優先級任務的工作;commit 階段的調度優先級採用的是最高優先級,以保證 commit 階段同步執行不可被打斷。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/MWm2KEiI-5tc-xoYqZ7Egw