React Fiber 浅谈

React Fiber

背景

React 为了描述组件状态和Dom的关系,采用虚拟DOM来表示真实DOM。
每个组件在每次渲染时会创建一个新的Virtual DOM,React会把新的Virtual DOM树与现有的相比较,然后将一系列转变应用于真实DOM。

在 React 15 的版本中,虚拟 Dom 采用 Stack 架构实现,diff 更新的过程是 同步循环递归,这就导致只有所有的 组件 更新之后,才会让出主进程进行 Dom 渲染。

虚拟 Dom 树如果直接更新,当组件非常多时,给数据更新的 diff 带来了很大压力。如果 js占据主线程去做比较,渲染线程便无法做其他工作,用户的交互得不到响应,所以便出现了react fiber。

什么是 Fiber

按照名词解释,这是一种数据结构(也可叫执行单元),将虚拟 Dom Tree 转变为 可支持·断点遍历重启 的 链表(单链表树结构)。

按照动词解释,这是协程,React Fiber 把一次更新过程碎片化,细致控制虚拟 Dom 更新 和 渲染 Dom 展示这些操作的执行顺序。

基于碎片化更新的过程,每次执行完单个碎片更新,就会把主线程交给 React 其他模块,来处理其他紧急任务。如果没有紧急任务,那就继续更新。

工作原理

Fiber 节点保存了 Dom 节点,Fiber 树和 Dom 树互相呼应。

通过判断当前执行帧空闲空间,来选择执行对应优先级的执行任务,在当前帧结束前再次判断是否有剩余时间和任务来支持执行,没有则执行浏览器渲染任务,并循环这一过程来最大化提升渲染效率。

利用requestAnimationFrame来确保每一帧执行的任务。

利用requestIdleCallback 来指定执行哪些低优先级的任务。如果遇到超过正常帧的任务,执行完毕后就需要立即归还控制权,并使用 requestIdleCallback 来再次申请下一次更新的时间片。requestIdleCallback 会给 callback 传递IdleDeadline 来判断任务的操作状态。

  • timeRamining():用来判断用户代理预计还剩余多少闲置时间。
  • didTimeout:用来判断当前的回调函数是否因超时而被执行。

双缓存 Fiber 树

  1. 基于渲染内容的 CurrentFiber Tree
  2. 内存中实时构建的 WorkInProgress Fiber Tree(节点之间通过 altermnate 属性连接)

根节点通过指针 current 在不同的 FiberTree 和 RootFiber 之间切换,完成 current Fiber Tree 指向的切换。

更新内容在 WorkInProgress Fiber Tree 构建完成后,经由 Renderer 渲染到页面上后,根节点的 current 指向 WorkInProgress Fiber 树,基于互相呼应的原理,这棵 WorkInProgress Fiber Tree 此时变成了 CurrentTree。当下一次 State 更新时,构建新的 WorkInProgress Fiber Tree, 然后再次执行上述操作,便完成了 Tree 的 替换,也就是 Dom 的更新

Render 阶段

此处的 Render 并非指浏览器渲染页面,而是虚拟 Dom 和 真实 Dom 的 Diff 过程,并进行变化的内容标记收集。**Render 是一个可以被打断的过程。 ** 在该阶段构建一棵Fiber tree,产生和虚拟 Dom 一一对应的任务,并且产出最后的更新 List(Effect List)。

收集 Effect List

  1. 如果当前节点需要更新,则使用对应tag标记当前节点状态(props, state, context等);
  2. 为每个子节点创建fiber。
    1. 并为 需要更新的 Fiber 添加两个属性:
      • firstEffect:指向第一个有变更的子fiber。
      • lastEffect:指向最后一个有变更的子fiber。

而我们需要收集的就是中间nextEffect,最终形成一个单链表。

  1. 如果没有产生child fiber,则结束该节点,把effect list归并到return,把此节点的兄弟节点作为下一个遍历节点;否则把子节点作为下一个遍历节点;
  2. 如果有剩余时间,则开始下一个节点,否则等下一次主线程空闲再开始下一个节点;
  3. 如果没有下一个节点了,进入pendingCommit状态,此时effect list收集完毕,结束。

Commit 阶段

Commit 阶段会将根据 EffectList 将上述操作中标记需要变更的 Fiber 更新到 DOM 树上,此阶段为了确保 UI 更新的连续性,是不可中断的过程。

到这里,整个 Fiber 的 刷新和更新过程就完成了。

总结

Fiber 是基于碎片化任务和和交替变更浏览器控制权,来达到更好的更新效果。其通过双缓存机制,在其 Render 阶段比较 虚拟 Dom 树和 真实 Dom,并进行节点变更标记和收集变更依赖,在 Commit 阶段更新 被标记 Fiber 节点到真实 Dom 树完成整个更新和刷新流程。

相关推荐
小桥风满袖2 小时前
极简三分钟ES6 - ES9中字符串扩展
前端·javascript
小Wang2 小时前
npm私有库创建(docker+verdaccio)
前端·docker·npm
用户73087011793083 小时前
Vue中集成文字转语音:使用Web Speech API实现功能
前端
李重楼3 小时前
前端性能优化之 HTTP/2 多路复用
前端·面试
yanessa_yu3 小时前
全屏滚动网站PC端自适应方案
前端
RoyLin3 小时前
TypeScript设计模式:桥接模式
前端·后端·typescript
火星开发者3 小时前
Vue中实现Word、Excel、PDF预览的详细步骤
前端
brzhang3 小时前
干翻 Docker?WebAssembly 3.0 的野心,远不止浏览器,来一起看看吧
前端·后端·架构
lecepin4 小时前
AI Coding 资讯 2025-09-17
前端·javascript·面试
IT_陈寒4 小时前
React 18实战:7个被低估的Hooks技巧让你的开发效率提升50%
前端·人工智能·后端