React理念------Fiber架构的主要原理
- [React 理念](#React 理念)
-
-
- [CPU 的瓶颈](#CPU 的瓶颈)
- [IO 的瓶颈](#IO 的瓶颈)
-
- Fiber的产生及原理
React 理念
从官网看到React的理念:
React 是用 JavaScript 构建快速响应的大型 Web 应用程序的首选方式。它在 Facebook 和 Instagram 上表现优秀。
可见,关键是实现快速响应。那么制约快速响应的因素是什么呢?
我们日常使用 App,浏览网页时,有两类场景会制约快速响应:
-
当遇到大计算量的操作或者设备性能不足使页面掉帧,导致卡顿。
-
发送网络请求后,由于需要等待数据返回才能进一步操作导致不能快速响应。
这两类场景可以概括为:
-
CPU 的瓶颈
-
IO 的瓶颈(网络延迟)
CPU 的瓶颈
当项目变得庞大、组件数量繁多时,就容易遇到 CPU 的瓶颈。
主流浏览器刷新频率为 60Hz,即每(1000ms / 60Hz)16.6ms 浏览器刷新一次。
我们知道,JS 可以操作 DOM,GUI渲染线程与JS线程是互斥的。所以JS 脚本执行和浏览器布局、绘制不能同时执行。
在每 16.6ms 时间内,需要完成如下工作:
JS脚本执行 ----- 样式布局 ----- 样式绘制
当 JS 执行时间过长 ,超出了 16.6ms,这次刷新就没有时间执行样式布局和样式绘制了。从而引起页面掉帧,造成卡顿。
如何解决这个问题呢?
答案是:在浏览器每一帧的时间中,预留一些时间给 JS 线程,React利用这部分时间更新组件 (可以看到,在源码中,预留的初始时间是 5ms)。这样浏览器就有剩余时间执行样式布局 和样式绘制,减少掉帧的可能性。
当预留的时间不够用时,React将线程控制权交还给浏览器使其有时间渲染 UI,React则等待下一帧时间到来继续被中断的工作。
这种将长任务分拆到每一帧中,像蚂蚁搬家一样一次执行一小段任务的操作,被称为时间切片(time slice)
解决CPU瓶颈的关键是实现时间切片,而时间切片的关键是:将同步的更新变为可中断的异步更新。
IO 的瓶颈
网络延迟是前端开发者无法解决 的。只能在网络延迟客观存在的情况下,减少用户对网络延迟的感知。
Fiber的产生及原理
React Fiber 是 React 16 中引入的一种新的协调机制(协程和双缓冲技术),用于实现增量式 、可中断 和可恢复 的异步更新方式,以提高 React 应用的性能和用户体验。
在传统的 React (React15及以前)渲染过程中,当进行组件的更新时,React 会从组件树的根节点开始递归遍历 ,计算出整个应用的新状态,并生成新的虚拟 DOM 树,最后将新旧虚拟 DOM 树进行对比,找出差异并进行更新。这个过程是同步的 ,一旦开始就无法中断,直到完成整个更新过程。如果组件树的层级很深,递归会占用线程很多时间,造成卡顿。
而 Fiber 的目标是将渲染过程拆分为多个可中断的小任务(fiber),并使用优先级调度算法 决定任务的执行顺序,使得浏览器在空闲时间内可以执行其他任务或响应用户交互。这种增量式的更新方式使得 React 应用更加响应快速,避免了长时间的阻塞。
在渲染过程中根据优先级和时间片(Time Slicing)等策略,将任务分配到不同的时间片段中执行,而不是一次性将整个渲染过程执行完毕。
具体实现上,React Fiber 使用了一个双缓存 技术。在任务执行过程中,React 会构建 Fiber 树,并使用两个链表结构分别表示当前任务的工作单元和下一次任务的工作单元。当时间片用尽或遇到优先级更高的任务时,React 可以中断当前任务,并将它保存到下一次任务的链表中。然后,React 可以恢复执行下一个任务,以此类推。
下面是 React Fiber 的主要原理和流程:
-
构建 Fiber 树:
React 在渲染过程中构建一棵 Fiber 树,它与组件树一一对应。每个 Fiber 节点包含了组件实例、组件的状态、要渲染的元素、子节点等信息。
-
协调阶段:
在协调阶段,React 遍历 Fiber 树,根据组件的更新优先级和调度算法 ,决定哪些 Fiber 节点需要进行更新,哪些可以跳过。这个过程是可中断的。
-
构建副作用链表:
在协调阶段完成后,React 根据更新的结果 构建一个副作用链表。副作用是对 DOM 的变更操作,如插入、更新或删除元素。副作用链表记录了所有需要在实际 DOM 更新阶段执行的操作。
-
提交阶段:
在提交阶段,React 会遍历副作用链表 ,根据副作用的类型和位置 ,执行实际的 DOM 更新操作 。这个过程是同步的,不能中断。
-
渲染结果:
在完成提交阶段后,React 会将更新后的结果渲染到屏幕上,并触发相应的生命周期方法和钩子函数。
React Fiber 的引入使得 React 应用的更新过程变得更加灵活和高效,能够更好地适应不同的设备和交互场景。同时,它也为 React 引入了更多的优化策略和扩展能力,如异步渲染、错误边界、懒加载等功能。
如何构建副作用链表
下面是构建副作用链表的主要过程:
初始化副作用链表:
在协调阶段结束后,React Fiber 会初始化一个空的副作用链表,用于记录更新过程中的副作用操作。
遍历 Fiber 树:
React Fiber 遍历 Fiber 树的过程中,对于每个需要更新的 Fiber 节点,会进行以下操作:
检查更新类型: React Fiber 根据节点的更新类型(如插入、更新或删除)来确定是否有副作用产生。根据更新类型的不同,会进行相应的副作用记录。
记录副作用: 如果节点有副作用产生,React Fiber 会将相关的操作记录到副作用链表中。这些操作可能包括对 DOM 的插入、更新或删除等。
遍历子节点: React Fiber 会继续遍历当前节点的子节点,重复上述步骤,直到遍历完整个 Fiber 树。
形成链表结构: 在遍历过程中,每个具有副作用的操作都会被记录到副作用链表中。这些操作会按照执行顺序依次连接形成一个链表结构。
返回副作用链表: 当遍历完成后,React Fiber 将最终形成的副作用链表返回,以便在提交阶段中执行实际的 DOM 更新操作。
通过构建副作用链表,React Fiber可以将更新操作的执行顺序记录下来,而不需要立即执行这些操作 。这样做的好处是可以对副作用进行批量处理,优化性能,并且在提交阶段时可以根据需要进行优化,如合并多个操作、减少DOM 访问次数等。这种机制帮助提高了 React 应用的渲染性能和用户体验。
参考:React技术揭秘