React不同版本源码的差异

React的理念

速度快,响应自然

React的架构

React15

  • Reconciler——找出发生变化的组件
  • Renderer——渲染发生变化的组件

Reconciler

React中会通过this.setState,this.forceUpdate,ReactDom.render等方法更新组件

  • 调用函数组件、class组件的render方法,将返回的JSX转换为虚拟DOM
  • 将虚拟DOM与上次的进行比较
  • 找出本次发生更新的虚拟DOM
  • 通知Renderer将变化的虚拟DOM渲染到页面上

Renderer

每次更新发生的时候,Renderer接收到Reconciler的通知,将变化的组件渲染到当前的宿主环境

React15的缺陷

无法支持同步更新
递归的去更新会导致某写情况下页面的渲染结果不一致

在Reconciler中,update的组件会调用updateComponent,mount的组件会调用mountComponent,这两个方法都是递归执行的

JS是一门单线程的语言,他的GUI渲染线程和JS主线程是互斥的,也就是说在页面执行我们的js代码的时候是不能够去渲染和绘制页面的,在我们渲染每一帧页面的时候:

JS代码执行-------样式布局-------样式绘制
  • 当JS代码执行的时间超过每一帧的时长的时候,页面上就无法反映出本次渲染的结果
  • 同时,对于React来说,因为递归执行的原因,所以会导致页面一旦开始更新就无法终止;如果我们页面的层级变得很深,就会导致递归更新的时间过长,页面无法渲染
  • Scheduler和Reconciler是交替渲染的

React16

React16的架构有三层:

  • Schduler(调度器)——调度人物的优先级,高优先级任务优先进入Reconciler
  • Reconciler(协调器)——找出变化的组件(Fiber架构?)
  • Renderer(渲染器)——将变化的组件渲染到页面上

其中Scheduler和Reconciler是平台无关的

Scheduler(调度器)

我们以浏览器每一帧是否有剩余时间作为任务中断的标准,需要有一种机制通知我们浏览器什么时候有剩余时间----requestIdleCallback
React实现了requestIdleCallback的polyfill---Scheduler;除了在浏览器空闲时间触发回调,还提供了多种调度优先级

Reconciler(协调器)

在React15中,Reconciler是递归处理虚拟DOM的
React16中更新的过程从递归变成了可以终中断的循环过程,每一次循环都回去调用shouleYield判断当前是否有剩余时间

function workLoopConcurrent() {
    while(workInProgress !== null && !shouldYield()) {
        workInProgress = performUnitOfWork(workInProgress)
    }
}

关于React15中的因为一些特殊原因导致中断更新的时候DOM渲染不完全的问题

在React16中,Reconciler和Renderer不是交替工作的。当Scheduler将任务交给Reconciler的时候,Reconciler会为变化的虚拟DOM搭上增/删/更新的标记

其他的标记
因为整个Scheduler和Reconciler的过程都是在内存中进行的。只有当组件都完成在Reconciler的工作,才会统一交给Renderer

Renderer(渲染器)

Renderer根据Reconciler为虚拟DOM的打上的标记,同步执行对应的DOM操作。
Scheduler和Reconciler中的步骤随时会因为,有更高优先级的任务进来,或者当前帧没有剩余时间而中断。因为 Scheduler和Reconciler中的工作都是在内存中进行的,并不会更新页面,所以即使这个里面出现反复中断,也不会影响用户的体验(看见部分DOM更新不完全)