React15 架构缺点
React16之前的版本比对更新虚拟DOM的过程是采用循环递归方式来实现的,这种比对方式有一个问题,就是一旦任务开始进行就无法中断,如果应用中数组数量庞大,主线程被长期占用,直到整颗虚拟DOM树比对更新完成之后主线程才被释放,主线程才能执行其他任务,这就会导致一些用户交互或动画等任务无法立即得到执行,页面就会产生卡顿,非常的影响用户体验。
主要原因就是递归无法中断,执行重的任务耗时较长,javascript又是单线程的,无法同时执行其他任务,导致任务延迟页面卡顿用户体验差。
React15架构可以分为两层:
- Reconciler(协调器)—— 负责找出变化的组件
- Renderer(渲染器)—— 负责将变化的组件渲染到页面
每当有更新发生时,Reconciler会做如下工作:
- 调用函数组件、或class组件的render方法,将返回的JSX转化为虚拟DOM
- 将虚拟DOM和上次更新时的虚拟DOM对比
- 通过对比找出本次更新中变化的虚拟DOM
- 通知Renderer将变化的虚拟DOM渲染到页面上
而React15使用的是栈调和器,由于递归执行,所以更新一旦开始,中途就无法中断。当调用层级很深时,递归更新时间超过了屏幕刷新时间间隔,用户交互就会卡顿。
react 16架构
React16架构可以分为三层:
- Scheduler(调度器)—— 调度任务的优先级,高优任务优先进入Reconciler
- Reconciler(协调器)—— 负责找出变化的组件
- Renderer(渲染器)—— 负责将变化的组件渲染到页面上
相比React15,16增加了一个Scheduler(调度器)
并发&调度(Concurrency & Scheduler)
Concurrency并发: 有能力优先处理更高优事务,同时对正在执行的中途任务可暂存,待高优完成后,再去执行。Scheduler协调调度: 在浏览器每一帧的时间中,预留一些时间给JS线程,React利用这部分时间更新组件,当预留的时间不够用时,React将线程控制权交还给浏览器使其有时间渲染UI,React则等待下一帧时间到来,继续被中断的工作。
在源码中,预留的初始时间是5ms
考虑到可中断渲染,并可重回构造。React自行实现了一套体系叫做 React fiber 架构。
Scheduler 运行核心点
-
有个任务队列
queue,该队列存放可中断的任务。 -
workLoop对队列里取第一个任务currentTask,进入循环开始执行。- 当该任务没有时间 或 需要中断 (渲染任务 或 其他高优任务插入等),则让出主线程。
-
requestAnimationFrame计算一帧的空余时间; -
使用
new MessageChannel ()执行宏任务;
Fiber架构
界面通过 vdom 描述,但是不是直接手写 vdom,而是 jsx 编译产生的 render function 之后以后生成的。这样就可以加上 state、props 和一些动态逻辑,动态产生 vdom。
vdom生成之后不再是直接渲染,而是先转成 fiber,这个vdom转fiber的过程叫做reconcile。
fiber 是一个链表结构,可以打断,这样就可以通过 requestIdleCallback 来空闲调度 reconcile,这样不断的循环,直到处理完所有的 vdom 转 fiber 的 reconcile,就开始 commit,也就是更新到 dom。
reconcile 的过程会提前创建好 dom,还会标记出增删改,那么 commit 阶段就很快了。
从之前递归渲染时做
diff来确定增删改以及创建dom,提前到了可打断的reconcile阶段,让commit变得非常快,这就是fiber架构的目的和意义。
Fiber的数据结构有三层信息: (采用链表结构)
-
实例属性
- 该Fiber的基本信息,例如组件类型等。
-
构建属性
- 构建属性 (
return、child、sibling)
- 构建属性 (
-
工作属性
- 数据的变更会导致UI层的变更
- 为了减少对
DOM的直接操作,通过Reconcile进行diff查找,并将需要变更节点,打上标签,变更路径保留在effectList里 - 待变更内容要有
Scheduler优先级处理 - 涉及到
diff等查找操作,是需要有个高效手段来处理前后变化,即双缓存机制。
链表结构即可支持随时随时中断的诉求
schedule就是通过空闲调度每个fiber节点的reconcile(vdom转fiber),全部reconcile完了就执行commit\。
React Fiber核心: 自行实现 虚拟栈帧。
总结
React16 使用的是全新的"Fiber调和器",这就依托于React16的重点了—Fiber架构。目前简要概括就是,React16能够实现中断调和,分批次异步地调和。从而达到不因为JS执行时间过久影响浏览器渲染。