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的源码各版本依旧在变更。

我写这篇的目的:

对于想去阅读源码的人为他们提供一个逻辑流程,个中细节他们能够本身慢慢研究(固然这也不是经过一篇两篇文章能描述完整的)

对于只是想了解下内部原理的人省去了理解大量细节处理的烦恼

相关文章
相关标签/搜索