React早就更新重构了,从v15升级到了v17,重构了整个架构。
这篇文章有点晚,但是还是记录一下吧,首先我们来聊聊v15。
React15架构
-
Reconciler(协调器)
按照某种规则,找到差异的组件。正如官网所说,当处理类似于this.setState、this.forceUpdate等API触发组件更新时,Reconciler都会按照我们所熟知的算法进行更新,决定是否进行挂载,修改,或者卸载操作,比如这样:
1.调用组件的render(),将返回的JSX转化为虚拟DOM
2.将此时的虚拟DOM和上次更新的DOM比较
3.通过diff算法,找出差异的虚拟DOM
4.通过Renderer将变化的虚拟DOM渲染到页面
在挂载mount组件的过程中,会调用mountComponent,而更新时会调用updateComponent,这两个操作都会递归的更新子组件
对,递归的更新!所以一旦开始,Reconciler和Renderer交替工作,当递归层级很深,渲染时就出现了嘎嘣脆,渲染和交互就会卡顿,所以就有了后面我们所说的Fiber reconciler。
-
Renderer(渲染器)
最初只用于渲染DOM,后来随着平台越来越多,比如React DOM(将组件渲染成DOM,即ReactDOM全局对象)React Native(渲染App原生组件),React Test(渲染JSON数,用于快照测试)等,它已经成为了管理工具,依据不同的底层平台管理React tree。
所以,按照这样的设计,并不能实现--用可中断的异步更新代替同步更新
React16
其实是在原有的基础上添加了Scheduler,并升级了Reconciler,采用了Fiber架构:
-
Scheduler(调度器)
协同调度,我们希望当浏览器有剩余的渲染时间时来通知js线程,同时具备调度优先级任务的机制,所以就有了Scheduler,正如官网所言,这是独立库,用于在浏览器环境下协同调度
-
Reconciler(协调器)
还记得我们ES6里的yield机制吗?对,就是它,更新渲染的机制从递归更新变成了可以中断的yield循环。也就是调用
shouldYield判断当前是否有剩余时间。
/** @noinline */function workLoopConcurrent() {// Perform work until Scheduler asks us to yield// 继续工作,知道Scheduler 让我们暂停while (workInProgress !== null && !shouldYield()) {workInProgress = performUnitOfWork(workInProgress);}}
同时它也做了架构上的更新:
-
能够把可中断的任务切片处理。
-
能够调整优先级,重置并复用任务。
-
能够在父元素与子元素之间交错处理,以支持 React 中的布局。
-
能够在
render()中返回多个元素。 -
更好地支持错误边界。
那么在渲染上做了哪些升级呢?见下图
在这个渲染过程中,Reconciler将更新的虚拟DOM打上代表增/删/更新的标记,类似这样:
// You can change the rest (and add more).export const Placement = /* */ 0b000000000000010;export const Update = /* */ 0b000000000000100;export const PlacementAndUpdate = /* */ 0b000000000000110;export const Deletion = /* */ 0b000000000001000;export const ContentReset = /* */ 0b000000000010000;export const Callback = /* */ 0b000000000100000;export const DidCapture = /* */ 0b000000001000000;export const Ref = /* */ 0b000000010000000;
Scheduler和Reconciler统一在内存中完成一系列处理以后,才交给renderer来进行渲染。
而图中大括号中的处理工作会因为浏览器中其他高级别任务或者没有剩余时间渲染而被中止(不是终止),但是由于是在内存中,所以并不会显示,等到下次帧渲染时再继续。
以上就是react架构升级的差异,当然,还有很多其他细节。
浙公网安备 33010602011771号