极客时间返利平台,你可以在上边通过山月的链接购买课程,并添加我的微信 (shanyue94) 领取返现。

# React 中 fiber 是用来做什么的

Issue

欢迎在 Gtihub Issue 中回答此问题: Issue 165 (opens new window)

因为 JavaScript 单线程的特点,每个同步任务不能耗时太长,不然就会让程序不会对其他输入作出相应,React 的更新过程就是犯了这个禁忌,而 React Fiber 就是要改变现状。 而可以通过分片来破解 JavaScript 中同步操作时间过长的问题。

把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。

React Fiber 把更新过程碎片化,每执行完一段更新过程,就把控制权交还给 React 负责任务协调的模块,看看有没有其他紧急任务要做,如果没有就继续去更新,如果有紧急任务,那就去做紧急任务。

维护每一个分片的数据结构,就是 Fiber。

Author

回答者: Feahter (opens new window)

React Fiber 是对核心算法的一次重新实现 Fiber reconciler 从 v16.x 开始底层使用 Fiber reconciler 替换 stack reconciler. 已知: stack reconciler 处理大状态时由于计算和组件树遍历的消耗容易出现渲染线程挂起,进而页面掉帧。(根本原因是渲染/更新过程一旦开始无法中断,持续占用主线程,主线程忙于执行 JS)

求: 建立一种能解决主线程占用问题,且具有长远意义的机制 解: 把渲染/更新过程拆分为小块任务,通过合理的调度机制来控制时间(更细粒度、更强的控制力)

子问题: 1.拆什么?什么不能拆? 把渲染/更新过程分为 2 个阶段(diff + patch): diffrender/reconciliation (对比 prevInstance 和 nextInstance 的状态,找出差异及其对应的 DOM change。) patchcommit (把本次更新中的所有 DOM change 应用到 DOM 树,是一连串的 DOM 操作。) render/reconciliation 阶段的工作(diff)可以拆分,commit 阶段的工作(patch)不可拆分.

2.怎么拆? Fiber 的拆分单位是 fiber(fiber tree 上的一个节点),实际上就是按虚拟 DOM 节点拆,因为 fiber tree 是根据 vDOM tree 构造出来的,树结构一模一样,只是节点携带的信息有差异。

3.如何调度任务? 分 2 部分:  工作循环  优先级机制 工作循环是基本的任务调度机制,工作循环中每次处理一个任务(工作单元),处理完毕有一次喘息的机会,此时通过 shouldYield 函数(idleDeadline.timeRemaining())判读时间是否用完,用完则把时间还给主线程等待下次 requestIdleCallback 的唤起,否则继续执行任务。 优先级机制用来处理突发事件与优化次序。 有如下策略:  到 commit 阶段了,提高优先级  高优任务做一半出错了,给降一下优先级  抽空关注一下低优任务,别给饿死了  如果对应 DOM 节点此刻不可见,给降到最低优先级 是工作循环的辅助机制。

4.如何中断/断点恢复? 中断:检查当前正在处理的工作单元,保存当前成果(firstEffect, lastEffect),修改 tag 标记一下,迅速收尾并再开一个 requestIdleCallback,下次有机会再做 断点恢复:下次再处理到该工作单元时,看 tag 是被打断的任务,接着做未完成的部分或者重做 自然中断(时间耗尽),或优先级中断(高优任务中断),原理相同。

5.如何收集任务结果? 每个节点更新结束时向上归并 effect list 来收集任务结果,reconciliation 结束后,根节点的 effect list 里记录了包括 DOM change 在内的所有 side effect。

requestIdleCallback 让开发者在主事件循环中执行后台或低优先级的任务,不会对动画和用户交互等关键事件产生影响。

fiber 架构:

  • 循环条件:利用 requestIdeCallback 空闲时间递减.
  • 遍历过程:利用链表,找孩子找兄弟找父亲.
Last Updated: 11/27/2021, 6:11:48 PM