react fiber簡單瞭解下

上一篇《知根知底setState》介紹了在不一樣場景調用setState會有不一樣的處理過程,但無論怎樣最終目的都是要進行react的更新,本文咱們就來了解setState以後的更新過程。
提示:源碼基於react v16.4.3-alpha.0react

須要瞭解的幾個函數

1, findHighestPriorityRoot

字面上意思能夠理解爲查找擁有最高優先級的root,這個root又是什麼呢?git

// react 項目的入口文件,初始化
ReactDom.render(
  <App />,
  document.getElementById('app')
)
複製代碼

root就是經過react生成的節點樹的根節點 <div id="app"></div>
做用:
1,找到擁有最高優先級的root
2,從更新任務鏈表中刪除沒有更新任務的root。這個沒有更新任務的root的怎麼理解呢——本來這個root的其中某個子節點觸發了更新,可是更新已經被處理完了,因此root.expirationTime === NoWork將已處理完成的去除掉github

2, addRootToSchedule

在findHighestPriorityRoot函數中能夠發現 firstScheduledRoot,lastScheduledRoot表示一個任務調度鏈表(環形)的頭結點和尾節點,那這個鏈表在哪裏生成的呢——addRootToSchedule源碼bash

3,requestWork

總結前兩個函數的功能:app

  • findHighestPriorityRoot —— 找到更新優先級最高的root,刪除已經更新完成的root
  • addRootToSchedule——有新的更新任務,將對應的root插入到任務調度鏈表

addRootToSchedule的調用位置就是在requestWork源碼
看過《知根知底setState》的同窗能夠知道在將setState的時候到這裏就結束了,爲何呢?由於接下來就是react fiber的Reconciler和Commit階段。異步

下面進入本文的主題了react fiber,從requestWork開始函數

一,requestWork

源碼oop

function requestWork(root: FiberRoot, expirationTime: ExpirationTime) {
  addRootToSchedule(root, expirationTime);
  
  ...
  
  if (expirationTime === Sync) {
    // 同步更新
    performSyncWork();
  } else {
    // 異步更新
    scheduleCallbackWithExpirationTime(root, expirationTime);
  }
}   
複製代碼

根據expirationTime判斷採用同步更新仍是異步更新,本文主要從同步更新的過程來了解fiberpost

二,performWork

// function performSyncWork() {
  performWork(Sync, null);
} 
複製代碼

performSyncWork僅僅只是調用performWork,注意第二個參數爲nullui

function performWork(minExpirationTime: ExpirationTime, dl: Deadline | null) {
  deadline = dl;
  
  // 保證每一次進行正在處理的更新任務都是優先級最高的
  findHighestPriorityRoot()
  
  if (deadline !== null) {
    // 處理同步更新
    
    // 在當前找到的優先級最高的root上開始後續的更新工做
    performWorkOnRoot(
      nextFlushedRoot,
      nextFlushedExpirationTime,
      currentRendererTime >= nextFlushedExpirationTime,
    );
  } else {
    // 處理異步更
  } 
}
複製代碼

從代碼中的if/else能夠發現雖然在requestWork中同步和異步走向兩個不一樣的分支,但最後又會合併到同一個處理過程performWork

三,performWorkOnRoot

準備好小板凳和瓜子終於到了fiber的正頭戲了,源碼

function performWorkOnRoot(
  root: FiberRoot,
  expirationTime: ExpirationTime,
  isExpired: boolean,
) {
  // 一樣有兩個分支——同步和異步

  if (deadline === null || isExpired) {
    // 同步的處理邏輯
    
    // 咱們知道fiber的Reconciler階段到Commit階段是能夠被中斷的
    // finishedWork就是Reconciler階段diff出來的反作用(新state生成的DOM)
    let finishedWork = root.finishedWork;
    
    if (finishedWork !== null) {
      // 不爲空說明以前有任務被中斷,須要如今處理完被中斷的任務
      completeRoot(root, finishedWork, expirationTime);
      
    } else {
      // 沒有被中斷的任務,就處理當前找到的優先級最高的更新任務
      
      root.finishedWork = null;
      
      // 是否能夠被中斷,對於同步和異步到期work不可被中斷
      const isYieldy = false;
      
      // Reconciler階段
      renderRoot(root, isYieldy, isExpired);
      
      // finishedWork其實就是rootWorkInProgress(新的VNode)
      finishedWork = root.finishedWork;
      
      if (finishedWork !== null) {
        // diff以後獲得的結果是:有更新,
        // 進入到Commit階段
        completeRoot(root, finishedWork, expirationTime);
      }
    }
    
  } else {
    // 異步的處理邏輯
  }
}
複製代碼

流程圖:

四,Reconciler階段

源碼

function renderRoot(
  root: FiberRoot,
  isYieldy: boolean,
  isExpired: boolean,
): void {
  
  ...

  if (
    expirationTime !== nextRenderExpirationTime ||
    root !== nextRoot ||
    nextUnitOfWork === null
  ) {
    // 檢查咱們是否從一個新堆棧開始,或者咱們是不是從以前的工做中恢復 
    ...
  }
  do {
    try {
      workLoop(isYieldy);
    } catch (thrownValue) {
      ...
    }
    // 執行一次就跳出循環
    break;
  } while (true);
}
複製代碼

workLoop

其實從執行setStateworkLoop若是你能理解,fiber的大概過程你也就理解了。workLoop以後的主要邏輯是進行diff——調用render前生命週期函數,應用新的state執行render獲得新的DOM,將要更新的信息掛在到rootWorkInProgress,並最後賦值給finishedWork。
這個過程的代碼量比較大,react大多數功能都是在這個階段進行的(如:ref,context等),固然這部分代碼邏輯比較直白式的理解起來也相對簡單,若是有興趣能夠自行研究下

五,Commit階段

源碼

function completeRoot(
  root: FiberRoot,
  finishedWork: Fiber,
  expirationTime: ExpirationTime,
): void {

  ...
  
  commitRoot(root, finishedWork);
}
複製代碼
function commitRoot(root: FiberRoot, finishedWork: Fiber): void {
  
  ...
  
  // 執行render以後的生命週期
  // 應用新state生成的Element(在diff階段經過createElement等建立)到DOM樹種
  
}

複製代碼

這個階段的邏輯起來也比較簡單,對這塊感興趣的同窗能夠自行研究下

結尾

結合《知根知底setState》和本文咱們粗略介紹了react v16的更新過程。

你可能會發現本文對一些實現細節沒有作過多的描述
這是由於對於fiber實現細節介紹的文章網上已經能夠搜索出不少,並且講的也比較詳細。

本文主要在同步更新的過程,異步更新和同步更新大多處理邏輯都是通用的,簡單說就以不一樣的方式進入到更新過程,並且react v16的源碼各版本依舊在變更。

我寫這篇的目的:

對於想去閱讀源碼的人爲他們提供一個邏輯流程,箇中細節他們能夠本身慢慢研究(固然這也不是經過一篇兩篇文章能描述完整的)

對於只是想了解下內部原理的人省去了理解大量細節處理的煩惱

相關文章
相關標籤/搜索