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 树完成整个更新和刷新流程。

相关推荐
web打印社区5 小时前
使用React如何静默打印页面:完整的前端打印解决方案
前端·javascript·vue.js·react.js·pdf·1024程序员节
喜欢踢足球的老罗5 小时前
[特殊字符] PM2 入门实战:从 0 到线上托管 React SPA
前端·react.js·前端框架
小光学长5 小时前
基于Vue的课程达成度分析系统t84pzgwk(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库·vue.js
Baklib梅梅6 小时前
探码科技再获“专精特新”认定:Baklib引领AI内容管理新方向
前端·ruby on rails·前端框架·ruby
南方以南_6 小时前
Chrome开发者工具
前端·chrome
YiHanXii6 小时前
this 输出题
前端·javascript·1024程序员节
楊无好6 小时前
React中ref
前端·react.js
程琬清君6 小时前
vue3 confirm倒计时
前端·1024程序员节
歪歪1007 小时前
在C#中详细介绍一下Visual Studio中如何使用数据可视化工具
开发语言·前端·c#·visual studio code·visual studio·1024程序员节
唔667 小时前
flutter实现web端实现效果
前端·flutter