帶你完全理解react fiber架構
先上一張整體架構圖
簡化了不少流程,這裏只取主要流程 node
主流程解說
- 從render函數起步,render函數第一個參數將接受一個vdom-tree。
- 經過scheduleRoot開始調度,shceduleRoot會使用到workInProgressRoot,nextUnitOfWork,currentRoot以及workInProgressRoot.alternate這幾個關鍵元素
- 咱們會經過requestIdleCallBack去執行wookloop(react中本身實現了該函數的polyfill,這裏不會講述)
- 經過! deadline.timeRemaining() < 1 && nextUnitOfWork,判斷時間片是否還有剩餘而且nextUnitOfWork任務還有剩餘去循環執行performUnitOfWork(nextUnitOfWork),該函數的做用是生成fiber-tree以及收集更新時的依賴。
- 以上調度過程就是能夠被打斷的,當沒有nextUnitOfWork時,將調用commitRoot更新頁面
wookloop的流程詳解
基於我發的總體架構圖react
- workLoop函數會首先判斷是否存在任務,而且該時間片是否使用完(在此咱們能夠先不考慮時間片使用完成的狀況),當任務存在,會調用performUnitOfWork,該函數會當即調用beginWork對當前fiberNode即nextUnitOfWork的子節點進行調和,生成新的fiber-tree。(這裏只是部分fiber-tree造成)
- 當該節點調和完成,react會將currentFiber指向他的child,並將該節點return出去賦值給nextUnitOfWork再次調用wookLoop直到child爲空。
- 此時從該節點開始收集依賴,(注意fiber-tree並無徹底造成),調用completeUnitOfWork(currentFiber)開始收集依賴,當該fiber-node依賴收集完成,react將該節點移向他的sibling節點,並將該節點賦值給nextUnitOfWork,再次調用performUnitOfWork,此時會生成該節點的fiber-tree,而且因爲sibling節點沒有child,將再次調用completeUnitOfWork收集該節點依賴。
- 在第3步中,若是sibling節點沒有,react將會移動當前節點到到其父節點,再次經過completeUnitOfWork收集父節點依賴。
- 重複3,4過程直到當前節點爲空,此時fiber-tree造成完成,依賴收集完成。
- 記住一點以上過程是經過requestIdleCallBack執行的,那麼以上過程即可以被打斷。
如何調和?
先上圖片 緩存
流程解說
- 首先根據是否存在oldFiber來判斷是不是第一次渲染,若是是接下來的判斷都屬於新增節點,若是不是那麼會更具新老節點的diff比對造成新的fiber-tree,
- 比對時咱們會順序遍歷新老節點,(源碼中會根據key造成map數據結構來比對節點)這裏的比對方式和官網給出的說法是一致的,這裏主要說的使一些性能上的優化,當react判斷是第一次更新(不是第一次渲染),他會複用oldFiber,若是是第二次或者更屢次更新,react會複用用緩存在alternate節點上的老節點,從而生成新的fiber-tree
- 調和的目的就是造成新的fiber-tree
收集依賴?
再來看一張圖片 數據結構
- 更具以上分析當開始調用completeUnitOfWork收集依賴時,該節點是最後一個child元素,從該元素開始,收集該元素的effect及其child的effect(最後一個元素無child)(整張圖就是這個意思)
- 按照自己--->兄弟節點---->父節點的順序向上遍歷,直到rootFiber節點全部依賴收集完畢。(根據整個架構圖推出)
提交fiberRoot
上圖: 架構
- 當收集完依賴,咱們開始執行commitRoot,首先咱們刪除須要刪除的節點,接着會從fistEffect開始遍歷更新頁面dom節點
- 調用commitWork(currentFiber)更新此fiber的dom節點,首先咱們會尋找到該fiber節點的第一個父容器dom節點,在更具該節點effectTag來更新、刪除或者除添加節點。
- 將effect指向下一個重讀2過程,直到全部effect遍歷完成。
歡迎關注本站公眾號,獲取更多信息