react16以后做了很大的改变,对diff算法进行了重写,从总体看,主要是把一次计算,改变为多次计算,在浏览器有高级任务时,暂停计算。
原理:从Stack Reconciler
到Fiber Reconciler
,源码层面其实就是干了一件递归改循环的事情
fiber设计目的:解决由于大量计算导致浏览器掉帧现象。
由于js是单线程的,解决主线程被长时间计算占用的问题,就是将计算分为多个步骤,分批完成,每完成一次计算就将主线程交还给浏览器,让页面有时间渲染。
react更新前后:
旧版:旧版 React 通过递归的方式进行渲染,使用的是 JS 引擎自身的函数调用栈,它会一直执行到栈空为止
新版:Fiber
实现了自己的组件调用栈,它以链表的形式遍历组件树,可以灵活的暂停、继续和丢弃执行的任务。实现方式是使用了浏览器的requestIdleCallback
这一 API。
React从框架层面有三个层级
Virtual DOM 层 | Virtual DOM 层,描述页面长什么样。 |
Reconciler 层 | 负责调用组件生命周期方法,进行 Diff 运算等。 |
Renderer 层 | 根据不同的平台,渲染出相应的页面,比较常见的是 ReactDOM 和 ReactNative。 |
为了加以区分,以前的 Reconciler 被命名为Stack Reconciler
。Stack Reconciler 运作的过程是不能被打断的,必须一条道走到黑。
为了达到这种效果,就需要有一个调度器 (Scheduler) 来进行任务分配。任务的优先级有六种:
- synchronous,与之前的Stack Reconciler操作一样,同步执行
- task,在next tick之前执行
- animation,下一帧之前执行
- high,在不久的将来立即执行
- low,稍微延迟执行也没关系
- offscreen,下一次render时或scroll时才执行
优先级高的任务(如键盘输入)可以打断优先级低的任务(如Diff)的执行,从而更快的生效。
Fiber 树
fiber reconciler在第一阶段diff时,会生成一棵树,这棵树是在virtual dom的基础上增加额外信息生成的,本质上是一个链表。
fiber tree首次渲染:一次生成
后续diff:根据virtual dom和已有tree生成新的tree,这棵树每生成一个节点,都会把控制权交给浏览器,去检查有没有优先级更高的任务需要执行。如果没有,则继续构建树的过程,如果过程中有优先级更高的任务需要进行,则 Fiber Reconciler 会丢弃正在生成的树。
总结:从Stack Reconciler
到Fiber Reconciler
,源码层面其实就是干了一件递归改循环的事情
参考:https://segmentfault.com/a/1190000018250127?utm_source=tag-newest