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

相关推荐
LuckyLay36 分钟前
使用 Docker 搭建 Rust Web 应用开发环境——AI教你学Docker
前端·docker·rust
pobu1681 小时前
aksk前端签名实现
java·前端·javascript
烛阴1 小时前
带参数的Python装饰器原来这么简单,5分钟彻底掌握!
前端·python
0wioiw01 小时前
Flutter基础(前端教程⑤-组件重叠)
开发语言·前端·javascript
冰天糖葫芦1 小时前
VUE实现数字翻牌效果
前端·javascript·vue.js
南岸月明1 小时前
我与技术无缘,只想副业搞钱
前端
gzzeason2 小时前
在HTML中CSS三种使用方式
前端·css·html
hnlucky2 小时前
《Nginx + 双Tomcat实战:域名解析、静态服务与反向代理、负载均衡全指南》
java·linux·服务器·前端·nginx·tomcat·web
huihuihuanhuan.xin2 小时前
前端八股-promise
前端·javascript
星语卿3 小时前
浏览器重绘与重排
前端·浏览器