理解React中Fiber架构(二)

简介: 自从React16版本更新了Hook用法,同时引入了新的Fiber架构去重构整个渲染和事件处理过程,React团队引入Hook是为了更好剥离业务代码,让开发能更加友好的抽象代码,达到低耦合的函数组件目的,那么重构Diff算法,引入Fiber架构是为了什么呢? 其实只是为了能够一个目标快速响应,原先Diff算法时间复杂度为O(n3) O(n^3)O(n3) ,最后经过Fiber重构达到了O(n)O(n)O(n),这里面具体有什么门道,值得我们去深入研究一下。

Stack Reconciler(栈协调器)


在了解Fiber架构之前,需要对React15的Stack Reconciler(栈协调器)做一次完整了解。先了解一下什么Reconciler协调器,在React中是这么定义的:

Virtual DOM 是一种编程概念。在这个概念里,UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中,并通过如 ReactDOM 等类库使之与“真实的” DOM 同步。这一过程叫作Reconciler 协调(调和)。

所以实现Reconciler,其实就是实现虚拟DOM到真实DOM渲染的整个逻辑过程,因此调和 !== Diff,但是Diff 确实是调和过程中最具代表性的一环。


那么要了解React15是如何实现Stack Reconciler,最重要的两块:

  • Diff算法策略
  • 找到diff节点并同步更新渲染


Diff算法策略要点:(主要是树递归)

1.Diff 算法性能突破的关键点在于“分层对比”;

2.类型一致的节点才有继续 Diff 的必要性;

3.key 属性的设置,可以帮我们尽可能重用同一层级内的节点。

Fiber架构


我们先来看看 React  团队在“React 哲学”中对 React 的定位:

我们认为,React 是用 JavaScript 构建快速响应的大型 Web 应用程序的首选方式。它在 Facebook 和 Instagram 上表现优秀。

快速响应是React哲学理念,因此Fiber架构的出现是为了让React框架能更加快速响应用户的操作。

是什么


什么是 Fiber?从字面上来理解,Fiber 这个单词翻译过来是“丝、纤维”的意思,是比线还要细的东西。在计算机科学里,我们有进程、线程之分,而 Fiber 就是比线程还要纤细的一个过程,也就是所谓的“纤程”。纤程的出现,意在对渲染过程实现更加精细的控制。


Fiber的概念理解:

  • 从架构角度来看,Fiber 是对 React 核心算法(即调和过程)的重写
  • 从编码角度来看,Fiber 是 React 内部所定义的一种数据结构,它是 Fiber 树结构的节点单位,也就是 React 16 新架构下的“虚拟 DOM”;
  • 从工作流的角度来看,Fiber 节点保存了组件需要更新的状态和副作用,一个 Fiber 同时也对应着一个工作单元。


从架构角度理解Fiber:

  • 架构核心:“可中断”“可恢复”与“优先级”
  • 可中断,指的是在Fiber架构下,任何工作任务都可以被更高优先级的任务中断
  • 可恢复,指的是被中断的任务可以被恢复继续执行
  • 优先级,指的是每个任务都有自己的优先级定义
  • 因此需要增加“Scheduler(调度器)”,作用是调度更新的优先级的任务

怎么解决问题


有了Fiber架构,怎么解决React15所面临的问题,虚拟DOM同步渲染真实DOM导致页面卡顿?

  • 将虚拟DOM,从原有的树结构,改为链表结构,拆分成一个个Fiber树节点
  • 利用Fiber架构,将渲染过程拆分成一个个工作单元任务,设置优先级,支持可中断、可恢复
  • 这样子当需要渲染复杂DOM时候,同时不影响其他优先级较高工作任务执行


当然这样子讲只是简单的原理,还需要弄明白异步后可能产生更多问题?比如如何定制优先级,当两个同样优先级的任务相遇的时候如何解决,这些放在第二章讲解。

总结


经过第一篇Fiber文章学习,大概了解到Fiber架构出现的背景和原因,以及它是什么,是如何工作的解决之前所遇到问题。简单总结一下:

  • React中定义Reconciler协调,指的是将虚拟DOM渲染到真实DOM的过程,React15之前采用是stack Reconciler栈协调,同步渲染机制导致页面卡顿
  • React16之后采用Fiber Reconciler,实现异步渲染DOM
  • 采用新的Fiber架构,同时影响到React的整个生命周期,主要是在更新阶段的生命周期

额外话题(Vue.js对比)


相比较React做Fiber架构优化,主要是针对事件做了时间分片,那么为什么Vue3(Vue@next)版本并不需要做呢?Vue.js作者尤雨溪是这样子回答的:

尤雨溪:在 Web 应用中,「可中断式更新」主要是由大量 CPU 计算加上复杂 DOM 操作引起的。时间分片旨在让应用在 CPU 进行大量计算时也能与用户交互,但时间分片只能对大量 CPU 计算进行优化,无法优化复杂 DOM 操作,因为要确保用户正在操作的界面是最新的状态才行。因此,我们可以考虑两种不同的可中断式更新的场景:

  1. 1.CPU 计算量不大,但 DOM 操作非常复杂(比如说你向页面中插入了十万个节点)。这种场景下不管你做不做时间分片,页面都会很卡。
  2. 2.CPU 计算量非常大。理论上时间分片在这种场景里会有较大收益,但是人机交互研究表明,除了动画之外,大部分用户不会觉得 10 毫秒和 100 毫秒有很大区别。 也就是说,时间分片只在 CPU 需要连续计算 100 毫秒以上的情况下才有较大收益。有意思的地方就出现了,在 React 经常会出现 100 毫秒以上的计算量,因为
  3. 3.Fiber 架构的复杂性导致 React 的虚拟 DOM 协调效率较低,这是系统性的问题。
  4. 4.React 使用 JSX 导致它的渲染效率比 template 低,因为 template 很容易做静态分析和优化。
  5. 5.React Hooks 将大部分组件树的优化 API 暴露给开发者,开发者很多时候需要手动调用 useMemo 来优化渲染效率。这意味着 React 应用默认就有 render 过多的问题。更严重的是,这些优化在 React 里很难自动化。
  6. 6.这些优化要求开发者正确设置依赖数组
  7. 7.盲目添加 useMemo 会导致应该 render 的没 render。 很不幸,大部分开发者都很懒,不会在每个地方都加上优化,因此大部分 React 应用都会有大量的没必要的 CPU 计算工作。 对比较而言,Vue 解决了上述问题:
  8. 8.Vue 的架构里没有时间分片,也就没有 Fiber,因此简单了很多,这使得渲染可以更快。
  9. 9.Vue 通过分析 template、简化协调过程,做了大量的 AOT 优化,性能测试结果表明大部分的 DOM 内容有 80% 属于静态内容,因此 Vue 3 的协调速度比 Svelte 快,花费的时间比 React 的 1/10 还少。
  10. 10.通过数据响应式追踪,Vue 可以做到组件树级别的优化,比如把插槽编译为函数以避免 children 的变化引发 re-render,比如自动缓存内联事件处理函数以避免 re-render。Vue 3 可以做到在不借助开发者的任何手动优化的情况下,防止子组件在非必要的情况下 re-render。这意味着同样一次更新,React 应用可能要 re-render 多个组件,而 Vue 应用很可能只 re-render 一个组件。 因此,在默认情况下,Vue 3 应用会比 React 应用少花费很多 CPU 时间,因而遇到 CPU 连续计算时间超过 100 毫秒的机会相当少,除非是极端情况。但大部分极端情况是 DOM 操作过于复杂,而不是 CPU 计算量太大。

进行汇总一下描述,Vue3之所以没有使用Fiber架构,主要有以下几个原因:

1.Vue.js针对template渲染机制做了多重优化,包括AOT优化(在构建的时候提前进行编译,提前将template转义成render函数)等,使得DOM元素渲染更快

2.复杂DOM渲染出现超过100ms以上的计算,是因为React本身机制导致,并不是所有复杂的DOM渲染都会需要100ms

3.React Hook的暴露增加渲染效率的复杂度,从而导致React渲染更慢,从而需要Fiber架构去协调

4.Vue数据响应式追踪机制,避免了多次重复render组件树,提高渲染效率

5.Vue使用Fiber架构去实现,确实可以有好处,但是会增加整体代码体积和复杂度,投入产出比太低

补充知识点


AOT vs JIT


  • AOT,Ahead Of Time,提前编译或预编译,宿主环境获得的是编译后的代码,在浏览器中我们可以直接下载并运行编译后的代码,比如:Vue的template是通过Vue-loader编译后才能使用。

  • JIT,Just In Time,即时编译 ,代码在宿主环境编译并执行,每个文件都是单独编译的,当我们更改代码时不需要再次构建整个项目,比如:React中JSX只有在浏览器运行的时候才知道具体代码。


目录
相关文章
|
10天前
|
前端开发 调度 UED
React 执行过程中 Fiber 的优先级是如何确定的?
【10月更文挑战第27天】React能够更加智能地管理任务的执行顺序,在保证用户交互体验的同时,充分利用系统资源,提高应用的整体性能和响应速度。
|
1月前
|
存储 前端开发 JavaScript
深入理解React Fiber架构及其性能优化
【10月更文挑战第5天】深入理解React Fiber架构及其性能优化
74 1
|
10天前
|
前端开发 JavaScript 调度
React 的 fiber
【10月更文挑战第26天】React Fiber 是 React 框架中的一个重要创新,它为 React 应用的性能优化和用户体验提升提供了强大的支持,使得 React 在处理复杂的前端应用场景时更加高效和灵活。
|
3月前
|
缓存 前端开发 算法
Fiber 架构如何提高性能和响应性的
【8月更文挑战第6天】Fiber 架构如何提高性能和响应性的
48 1
|
3月前
|
缓存 前端开发 JavaScript
理解 React 的 Fiber 架构
【8月更文挑战第6天】 理解 React 的 Fiber 架构
164 1
|
6月前
|
前端开发 NoSQL 数据库
切图仔做全栈:React&Nest.js社区平台(一)——基础架构与邮箱注册、JWT登录实现
切图仔做全栈:React&Nest.js社区平台(一)——基础架构与邮箱注册、JWT登录实现
|
移动开发 JavaScript Java
|
6月前
|
设计模式 前端开发 数据可视化
【第4期】一文了解React UI 组件库
【第4期】一文了解React UI 组件库
352 0
|
6月前
|
存储 前端开发 JavaScript
【第34期】一文学会React组件传值
【第34期】一文学会React组件传值
73 0
|
6月前
|
资源调度 前端开发 JavaScript
React 的antd-mobile 组件库,嵌套路由
React 的antd-mobile 组件库,嵌套路由
119 0