「源码学习」三、v16的React架构

260 阅读2分钟

React16的架构分为三层:

  • Scheduler(调度器)—— 调度任务的优先级,高优任务优先进入Reconciler
  • Fiber Reconciler(协调器)—— 负责找出变化的组件
  • Renderer(渲染器)—— 负责将变化的组件渲染到页面上

相较于React15,React16中新增了Scheduler(调度器)

Scheduler(调度器)

既然我们以浏览器是否有剩余时间作为任务中断的标准,那么我们需要一种机制,当浏览器有剩余时间时通知我们。

其实部分浏览器已经实现了这个API,这就是requestIdleCallback

但是因为

  • 浏览器兼容性
  • 触发频率不稳定,受很多因素影响。比如当我们的浏览器切换tab后,之前tab注册的requestIdleCallback触发的频率会变得很低

所以,React放弃了这个api,转而自己实现了一个功能更加完善的。除了在空闲时触发回调的功能外,Scheduler还提供了多种调度优先级供任务设置。

Reconciler(协调器)

在react15中,协调器是递归的,而在react16中,协调器就是可中断的循环过程。每次循环都会调用shouldYield判断当前是否有剩余时间。

/** @noinline */
function workLoopConcurrent() {
  // Perform work until Scheduler asks us to yield
  while (workInProgress !== null && !shouldYield()) {
    workInProgress = performUnitOfWork(workInProgress);
  }
}

那么React16是如何解决中断更新时DOM渲染不完全的问题呢?

在React16中,ReconcilerRenderer不再是交替工作。当Scheduler将任务交给Reconciler后,Reconciler会为变化的虚拟DOM打上代表增/删/更新的标记,类似这样:

export const Placement = /*             */ 0b0000000000010;
export const Update = /*                */ 0b0000000000100;
export const PlacementAndUpdate = /*    */ 0b0000000000110;
export const Deletion = /*              */ 0b0000000001000;

整个SchedulerReconciler的工作都在内存中进行。只有当所有组件都完成Reconciler的工作,才会统一交给Renderer

Renderer(渲染器)

Renderer根据Reconciler为虚拟DOM打的标记,同步执行对应的DOM操作。

React16 架构的整个更新流程:

**Scheduler **接收到更新后,先会判断有没有其他高优先级的任务需要执行,如果有就去执行,没有就将更新通知到Reconciler。

Reconciler接收到任务后,就开始循环,每次循环都会调用shouldYield判断当前是否有剩余时间,如果有继续执行,它会为变化的虚拟DOM打上代表增/删/更新的标记,如果没有那就暂停执行,等到下一个时间帧再执行。

当所有的组件都完成Reconciler打标记的动作之后,才会统一去做Renderer渲染。