日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

React 调和(Reconciler)原理理解

發布時間:2024/1/8 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 React 调和(Reconciler)原理理解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • Fiber
    • Fiber 更新機制
      • 雙緩沖樹
    • render階段
    • commit 階段
    • 總結

Fiber

Reactv15及之前,React 對于虛擬 DOM 是采用 遞歸方式 遍歷更新的,一次更新,從應用根部遞歸更新,遞歸開始后中途無法終端,隨著項目復雜,層級變深,導致更新時間變成,給前端交互上的體驗就卡頓。

Fiber 誕生在 Reactv16 版本,Fiber 架構目的就是解決大型 React 應用卡頓,fiber 在 React 中是最小粒度的執行單元,在遍歷更新每一個節點的時候都不是用的真實 DOM ,都是采用虛擬 DOM ,所以可以 理解成 fiber 就是 React 的虛擬 DOM

Fiber解決:

  • 更新 fiber 的過程叫做 Reconciler(調和器),每一個 fiber 可以作為一個 執行單元 來處理,所以每一個 fiber 可以根據自身的過期時間 expirationTime( v17 版本叫做優先級 lane )來判斷是否還有空間時間執行更新。
  • 如果沒有時間更新,就要把主動權交給瀏覽器去渲染,做一些動畫,重排( reflow ),重繪(repaints) 等。
  • 等瀏覽器空余時間,再通過 Scheduler (調度器),再次恢復執行單元。在本質上中斷了渲染,提升用戶體驗。

element、fiber、dom 三者間關系:

  • element 是 React 視圖層在代碼層級上的表象,也就是開發者寫的 jsx 語法,寫的元素結構,都會被創建成 element 對象的形式。上面保存了 props , children 等信息。
  • dom 是元素在瀏覽器上給用戶直觀的表象。
  • fiber 可以理解為 element 和真實 dom 之間的交流樞紐站,每一個類型 element 都會有一個與之對應的 fiber 類型,element 變化引起更新流程都是通過 fiber 層面做一次調和改變,然后對于元素,形成新的 dom 做視圖渲染。

element 與 fiber 之間的對應關系:

fiberelement
FunctionComponent = 0函數組件
ClassComponent = 1類組件
IndeterminateComponent = 2初始化的時候不知道是函數組件還是類組件
HostRoot = 3Root Fiber 可以理解為根元素 , 通過reactDom.render()產生的根元素
HostPortal = 4ReactDOM.createPortal 產生的 Portal
HostComponent = 5dom 元素 比如
HostText = 6文本節點
Fragment = 7<React.Fragment>
Mode = 8<React.StrictMode>
ContextConsumer = 9<Context.Consumer>
ContextProvider = 10<Context.Provider>
`ForwardRef = 11React.ForwardRef
Profiler = 12<Profiler>
SuspenseComponent = 13<Suspense>
MemoComponent = 14React.memo 返回的組件

fiber 保存信息:

function FiberNode(){this.tag = tag; // fiber 標簽 證明是什么類型fiber。this.key = key; // key調和子節點時候用到。 this.type = null; // dom元素是對應的元素類型,比如div,組件指向組件對應的類或者函數。 this.stateNode = null; // 指向對應的真實dom元素,類組件指向組件實例,可以被ref獲取。this.return = null; // 指向父級fiberthis.child = null; // 指向子級fiberthis.sibling = null; // 指向兄弟fiber this.index = 0; // 索引this.ref = null; // ref指向,ref函數,或者ref對象。this.pendingProps = pendingProps;// 在一次更新中,代表element創建this.memoizedProps = null; // 記錄上一次更新完畢后的propsthis.updateQueue = null; // 類組件存放setState更新隊列,函數組件存放this.memoizedState = null; // 類組件保存state信息,函數組件保存hooks信息,dom元素為nullthis.dependencies = null; // context或是時間的依賴項this.mode = mode; //描述fiber樹的模式,比如 ConcurrentMode 模式this.effectTag = NoEffect; // effect標簽,用于收集effectListthis.nextEffect = null; // 指向下一個effectthis.firstEffect = null; // 第一個effectthis.lastEffect = null; // 最后一個effectthis.expirationTime = NoWork; // 通過不同過期時間,判斷任務是否過期, 在v17版本用lane表示。this.alternate = null; //雙緩存樹,指向緩存的fiber。更新階段,兩顆樹互相交替。 }

fiber建立起關聯:

每一個 element 都會對應一個 fiber ,每一個 fiber 是通過 return , child ,sibling 三個屬性建立起聯系的。

  • return: 指向父級 Fiber 節點。
  • child: 指向子 Fiber 節點。
  • sibling:指向兄弟 fiber 節點。

Fiber 更新機制

1、初始化

第一步:創建 fiberRoot 和 rootFiber

  • fiberRoot:首次構建應用, 創建一個 fiberRoot ,作為整個 React 應用的根基。
  • rootFiber: 通過 ReactDOM.render 渲染出來的。

注意:一個 React 應用可以有多 ReactDOM.render 創建的 rootFiber ,但是只能有一個 fiberRoot(應用根節點)

第二步:workInProgress和current

開始到正式渲染階段,會進入 beginwork 流程

  • workInProgress:正在內存中構建的 Fiber 樹稱為 workInProgress Fiber 樹。在一次更新中,所有的更新都是發生在 workInProgress 樹上。在一次更新之后,workInProgress 樹上的狀態是最新的狀態,那么它將變成 current 樹用于渲染視圖。
  • current:正在視圖層渲染的樹叫做 current Fiber樹

rootFiber 的渲染流程: 首先會復用當前 current 樹( rootFiber )的 alternate 作為 workInProgress 。如果沒有 alternate (初始化的 rootFiber 是沒有 alternate ),那么會創建一個 fiber 作為 workInProgress會用 alternate 將新創建的 workInProgress 與 current 樹建立起關聯

currentFiber.alternate = workInProgressFiberworkInProgressFiber.alternate = currentFiber


第三步:深度調和子節點,渲染視圖

在新創建的 alternates 上,完成整個 fiber 樹的遍歷,包括 fiber 的創建。

最后會以 workInProgress 作為最新的渲染樹,fiberRoot 的 current 指針指向 workInProgress 使其變為 current Fiber 樹。到此完成初始化流程。


2、更新

首先會重新創建 workInProgresss 樹,復用當前 current 樹上的 alternate ,作為新的 workInProgress

由于初始化 rootfiber 有 alternate ,所以對于剩余的子節點,React 還需要創建一份,和 current 樹上的 fiber 建立起 alternate 關聯。

渲染完畢后,workInProgresss 再次變成 current 樹。

總結:

① 每一個 fiber 可以看作一個執行的單元。

② 在調和過程中,每一個發生更新的 fiber 都會作為一次 workInProgress 。

雙緩沖樹

問題:canvas 繪制動畫的時候,如果上一幀計算量比較大,導致清除上一幀畫面到繪制當前幀畫面之間有較長間隙,就會出現白屏。

解決: canvas 在內存中繪制當前動畫,繪制完畢后直接用當前幀替換上一幀畫面,由于省去了兩幀替換間的計算時間,不會出現從白屏到出現畫面的閃爍情況。

這種在內存中構建并直接替換的技術叫做 雙緩存

React 用 workInProgress 樹(內存中構建的樹)current (渲染樹) 來實現更新邏輯。雙緩存一個 在內存中構建,一個 渲染視圖,兩顆樹用 alternate 指針相互指向,在下一次渲染的時候,直接復用緩存樹做為下一次渲染樹,上一次的渲染樹又作為緩存樹,這樣可以 防止只用一棵樹更新狀態的丟失的情況,又加快了 DOM 節點的替換與更新。

render階段

1、workLoop

fiber 的遍歷開始—— workLoop,workLoop 就是執行每一個單元的 調度器,如果渲染沒有被中斷,那么 workLoop 會遍歷一遍 fiber 樹。


2、performUnitOfWork

performUnitOfWork 包括兩個階段 beginWorkcompleteWork

  • beginWork:是 向下調和 的過程。就是由 fiberRoot 按照 child 指針逐層向下調和,期間會執行函數組件,實例類組件,diff 調和子節點,打不同 effectTag
  • completeUnitOfWork:是 向上歸并 的過程。如果有兄弟節點,會返回 sibling兄弟,沒有返回 return 父級,一直返回到 fiebrRoot ,期間可以形成 effectList,對于初始化流程會創建 DOM ,對于 DOM 元素進行事件收集,處理style,className等。

3、beiginWork


beiginWork 作用:

  • 對于組件,執行部分生命周期,執行 render ,得到最新的 children 。
  • 向下遍歷調和 children ,復用 oldFiber ( diff 算法)
  • 打不同的副作用標簽 effectTag ,比如類組件的生命周期,或者元素的增加,刪除,更新。

常用的 effectTag:

effectTag含義
Placement =0b0000000000010插入節點
Update = 0b0000000000100更新fiber
Deletion = 0b0000000001000刪除fiebr
Snapshot = 0b0000100000000快照
Passive =0b0001000000000useEffect的副作用
Callback =0b0000000100000setState的 callback
Ref = 0b0000010000000ref

4、completeUnitOfWork

  • completeUnitOfWork 會將 effectTag 的 Fiber 節點會被保存在一條被稱為 effectList 的單向鏈表中。在 commit 階段,將不再需要遍歷每一個 fiber ,只需要執行更新 effectList 。
  • 對于組件處理 context ;對于元素標簽初始化,會創建真實 DOM ,將子孫 DOM 節點插入剛生成的 DOM 節點中;會觸發 diffProperties 處理 props ,比如事件收集,style,className 處理。

commit 階段

  • 一方面是 對一些生命周期和副作用鉤子的處理,比如 componentDidMount ,函數組件的 useEffect ,useLayoutEffect ;
  • 另一方面就是 在一次更新中,添加節點( Placement ),更新節點( Update ),刪除節點( Deletion ),還有就是 一些細節的處理,比如 ref 的處理。

commit 可以分為:

  • Before mutation 階段(執行 DOM 操作前);
  • mutation 階段(執行 DOM 操作);
  • layout 階段(執行 DOM 操作后)

1、Before mutation

  • 還沒修改真實的 DOM ,是 獲取 DOM 快照的最佳時期,如果是類組件有 getSnapshotBeforeUpdate ,那么會執行這個生命周期。
  • 異步調用 useEffect , useEffect 是采用異步調用的模式,其目的就是 防止同步執行時阻塞瀏覽器做視圖渲染。

2、Mutation

  • 置空 ref ,對于 ref 的處理。
  • 對新增元素,更新元素,刪除元素。進行真實的 DOM 操作

3、Layout

  • commitLayoutEffectOnFiber 對于類組件,會執行生命周期setState 的callback,對于函數組件會執行 useLayoutEffect 鉤子
  • 如果有 ref ,會 重新賦值 ref

調和+異步調度 原理圖

總結

1、Fiber組成

2、Fiber 更新機制(初始化和更新)、雙緩沖樹

3、Fiber 調和過程(render和commit階段)

總結

以上是生活随笔為你收集整理的React 调和(Reconciler)原理理解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。