React15到React16就是为了更好的实现React的理念——快速响应。必须要做到:可中断!

# React 15 到 React 16

之前已经了解到了React的理念就是快速响应,而React16的由来就是因为React15并不能很好的满足快速响应的理念,所以我们先来看看React15的缺点。

# 老的React15架构

React15架构可以分为两层:

  • Reconciler(协调器)—— 负责找出变化的组件
  • Renderer(渲染器)—— 负责将变化的组件渲染到页面上

# 1.Reconciler(协调器)

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

  • 调用函数组件、或class组件的render方法,将返回的JSX转化为虚拟DOM
  • 将虚拟DOM和上次更新时的虚拟DOM对比
  • 通过对比找出本次更新中变化的虚拟DOM
  • 通知Renderer将变化的虚拟DOM渲染到页面上

# 2.Renderer(渲染器)

不同平台有不同的Renderer。我们前端最熟悉的是负责在浏览器环境渲染的Renderer —— ReactDOM (opens new window)

Renderer的作用就是在每次更新发生时,Renderer接到Reconciler通知,将变化的组件渲染在当前的环境。

# 3.React15架构的缺点

React15的架构是通过递归更新来实现的,挂载的组件调用mountComponent,更新的组件调用updateComponent,这两个方法都会递归更新子组件,那这样的递归更新是无法中断的,并且ReconcilerRenderer是交替工作的,违背了刚刚我们所说的React解决快速响应的方法——用可中断的异步更新代替同步的更新,具体可以看React理念 (opens new window)这一篇,于是乎React重写了整个架构

# 新的React16架构

React16架构可以分为三层:

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

可以看到,相较于React15,React16中新增了Scheduler(调度器),让我们来了解下他。

# 1. Scheduler(调度器)

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

Scheduler会接收需要更新的任务,在浏览器有剩余时间时触发回调,并且提供了多种调度优先级,可以设置给任务。高优先级的任务可以随时打断正在进行中的低优先级任务。

# 2.Reconciler(协调器)

我们知道,在React15中Reconciler是递归处理虚拟DOM的。而React16中,更新工作从递归变成了可以中断的循环过程。每次循环都会调用shouldYield判断当前是否有剩余时间。

那么如果中断更新时,DOM渲染不完全呢?这会导致页面出现异常。

所以React16中的ReconcilerRenderer不再是交替工作了,而是Scheduler江任务交给Reconciler后,Reconciler会为这些变化的虚拟DOM打上某个代表操作类型(增删改)的标记,将所有的组件都完成Reconciler的工作后,将统一交给Renderer去渲染

# 3.Renderer(渲染器)

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

# 总结

总的来说,React15->React16发生的变化就是如下:

  • 新增Scheduler,负责监听需要完成的任务,并且有了优先级,高优先级任务打断低优先级任务
  • 不再是交替着工作,而是Reconciler根据Scheduler的任务进行判断,将所有需要更改的虚拟DOM全找出来之后,再统一交给Renderer
  • 不再是递归更新,导致无法中断。SchedulerReconciler的工作随时都可以中断,并且因为Renderer并没有收到要更新的消息,页面也不会有异常变化。