https://juejin.cn/post/6943896410987659277 1️⃣ 优化每个任务,让它有多快就多快。挤压CPU运算量 2️⃣ 快速响应用户,让用户觉得够快,不能阻塞用户的交互 3️⃣ 尝试 Worker 多线程

在 react16 引入 Fiber 架构之前,react 会采用递归对比虚拟DOM树,找出需要变动的节点,然后同步更新它们,这个过程 react 称为reconcilation(协调)。在reconcilation期间,react 会一直占用浏览器资源,会导致用户触发的事件得不到响应。实现的原理如下所示:这种遍历是递归调用,执行栈会越来越深,而且不能中断,中断后就不能恢复了。递归如果非常深,就会十分卡顿。如果递归花了100ms,则这100ms浏览器是无法响应的,代码执行时间越长卡顿越明显。传统的方法存在不能中断和执行栈太深的问题。

Vue 是基于 template 和 watcher 的组件级更新,把每个更新任务分割得足够小,不需要使用到 Fiber 架构,将任务进行更细粒度的拆分 React 是不管在哪里调用 setState,都是从根节点开始更新的,更新任务还是很大,需要使用到 Fiber 将大任务分割为多个小任务,可以中断和恢复,不阻塞主进程执行高优先级的任务

🔴为了给用户制造一种应用很快的'假象',我们不能让一个程序长期霸占着资源. 你可以将浏览器的渲染、布局、绘制、资源加载(例如HTML解析)、事件响应、脚本执行视作操作系统的'进程',我们需要通过某些调度策略合理地分配CPU资源,从而提高浏览器的用户响应速率, 同时兼顾任务执行效率。

何为 Fiber Fiber 可以理解为是一个执行单元,也可以理解为是一种数据结构。 Fiber 可以被理解为划分一个个更小的执行单元,它是把一个大任务拆分为了很多个小块任务,一个小块任务的执行必须是一次完成的,不能出现暂停,但是一个小块任务执行完后可以移交控制权给浏览器去响应用户,从而不用像之前一样要等那个大任务一直执行完成再去响应用户。

首先 React 向浏览器请求调度,浏览器在一帧中如果还有空闲时间,会去判断是否存在待执行任务,不存在就直接将控制权交给浏览器,如果存在就会执行对应的任务,执行完成后会判断是否还有时间,有时间且有待执行任务则会继续执行下一个任务,否则就会将控制权交给浏览器。

requestIdleCallback 也是 react Fiber 实现的基础 api 。我们希望能够快速响应用户,让用户觉得够快,不能阻塞用户的交互,requestIdleCallback能使开发者在主事件循环上执行后台和低优先级的工作,而不影响延迟关键事件,如动画和输入响应。正常帧任务完成后没超过16ms,说明有多余的空闲时间,此时就会执行requestIdleCallback里注册的任务。 具体的执行流程如下,开发者采用requestIdleCallback方法注册对应的任务,告诉浏览器我的这个任务优先级不高,如果每一帧内存在空闲时间,就可以执行注册的这个任务。另外,开发者是可以传入timeout参数去定义超时时间的,如果到了超时时间了,浏览器必须立即执行,使用方法如下:window.requestIdleCallback(callback, { timeout: 1000 })。浏览器执行完这个方法后,如果没有剩余时间了,或者已经没有下一个可执行的任务了,React应该归还控制权,并同样使用requestIdleCallback去申请下一个时间片。具体的流程如下图:

Fiber执行原理 从根节点开始渲染和调度的过程可以分为两个阶段:render 阶段、commit 阶段。

render 阶段:这个阶段是可中断的,会找出所有节点的变更 commit 阶段:这个阶段是不可中断的,会执行所有的变更

render阶段 1 此阶段会找出所有节点的变更,如节点新增、删除、属性变更等,这些变更 react 统称为副作用(effect),他会为需要更新的内容对应的fiber(可以理解为虚拟DOM)打上标记,此阶段会构建一棵Fiber tree,以虚拟dom节点为维度对任务进行拆分,即一个虚拟dom节点对应一个任务,最后产出的结果是effect list,从中可以知道哪些节点更新、哪些节点增加、哪些节点删除了。

2 接下来定义一个递归函数,从根节点出发,把全部的 fiber 节点遍历一遍,产出最终全部的effect list:

3 根据一个 fiber 的effect list列表去更新视图(这里只列举了新增节点、删除节点、更新节点的三种操作)

commit阶段 commit 阶段需要将上阶段计算出来的需要处理的副作用一次性执行,此阶段不能暂停,否则会出现UI更新不连续的现象。此阶段需要根据effect list,将所有更新都 commit 到DOM树上。

useEffect的执行顺序 React的源码可以拆分为三块:

调度器:调度更新 协调器:决定更新的内容 渲染器:将更新的内容渲染到视图中

上次更新:
贡献者: 郑壮