一、reactv16之前的架构

reactv15的架构可分为两部分:

  • reconciler(协调器) - 负责找出变化组件
  • renderer(渲染器) - 负责将变化的组件渲染到页面

在React中可以通过this.setState、this.forceUpdate、ReactDOM.render等API触发更新。

reconciler

每当有更新发生时,reconciler会如下工作:

  • 调用函数组件、或者render方法,将返回的jsx转化成v-dom
  • 将v-dom和上次更新时到v-dom对比
  • 通过对比找出本次更新中变化到v-dom
  • 通知renderer将变化v-dom渲染到页面

renderer

不同到平台有不同到渲染器,react-dom、react-native、react-art和react-test等。

缺点

reconciler在,mount组件会调用mountComponent,update的组件会调用updateComponent。者两个方法都会递归更新子组件。

由于递归执行,所以一旦开始,中途就无法中断,当层级很深时,递归更新超过16ms,用户交互就会卡顿。

二、reactv16的架构

react16的架构可分为三层:

  • scheduler(调度器)- 调度任务的优先级,高优任务先进入reconciler
  • reconciler(协调器)- 负责找出变化的组件
  • renderer(渲染器)- 负责将变化的组件渲染到页面上

scheduler

由于部分浏览器requestIdleCallback这个api兼容性和触发频率不稳定到问题,react放弃浏览器的该api。
基于这个原因react实现了功能更完备的requestIdleCallback polyfill,也就是scheduler。除了在空闲时触发回调的功能外,Scheduler还提供了多种调度优先级供任务设置。

reconclier

react16的reconciler的更新工作从递归变成了可以中断的循环过程。具体表现在每次循环都会调用shouldYield判断当前是否有剩余时间。

如:

1
2
3
4
5
6
7
/** @noinline */
function workLoopConcurrent() {
// Perform work until Scheduler asks us to yield
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}

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

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

1
2
3
4
5
6
export const Placement = /*                    */ 0b000000000000000010;
export const Update = /* */ 0b000000000000000100;
export const PlacementAndUpdate = /* */ 0b000000000000000110;
export const Deletion = /* */ 0b000000000000001000;
export const ContentReset = /* */ 0b000000000000010000;
export const Callback = /* */ 0b000000000000100000;

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

renderer

renderer根据reconciler为v-dom打的标记,同步执行对应组件更新。

墙裂推荐资料

React技术揭秘