React Fiber
React Fiber 架构原理剖析-SegmentFault
React Fiber 是 React 16 中引入的一种新的协调算法,被称为 Fiber Reconciler
,基于 Fiber
节点实现,支持可中断异步更新。
React Fiber 的工作原理是将协调过程分解为更小的工作单元,称为纤程。纤程可以按任何顺序调度和执行,这使得 React 可以确定工作的优先级并避免阻塞主线程。
将复杂任务分块处理,并根据重要性对任务进行优先排序
概念
调度器(Scheduler)、协调器(Reconcilers)、渲染器(Rendered),Reconciler
内部采用了Fiber
的架构
双缓存:WokeInProgress、current
旧协调器:stack reconciler.
reconciliation:这种递归遍历树以了解React应用组件树的底层DOM标签元素的确切过程被称为 reconciliation
render 阶段会找到 vdom 中变化的部分,创建 dom,打上增删改的标记,这个叫做 reconcile。
Reconciler
工作的阶段被称为render
阶段。因为在该阶段会调用组件的render
方法。Renderer
工作的阶段被称为commit
阶段。就像你完成一个需求的编码后执行git commit
提交代码。commit
阶段会把render
阶段提交的信息渲染在页面上。
在新的架构中,更新工作从递归变成了可以中断的循环过程。每次循环都会调用shouldYield
判断当前是否有剩余时间。
更新首先会被【调度器】处理,在调度器中会调度这些更新的优先级,更高优的更新会首先进入协调器,在本次更新的 Reconcile
中正在执行 Diff 算法时,如果此时产生了更高优先级的更新,本次正在协调的更新会被中断,由于 Scheduler
和 Reconcile
都是在视图中完成的操作,因此即使更新中断,用户也不会看到更新不完整的视图。当某次更新完成了 Reconcile
中的工作时,协调器会通知渲染器,本次更新有哪些组件需要执行对应的视图操作(CRUD),当渲染器完成了它的工作,调度器又会开始新一轮的调度
Firber 节点表示一个 react element,属性有:type、key、child、return、sibling、Alternate、output
一个 fiber 节点就是最小的任务单元,reconcile 阶段每次处理一个 fiber 节点,处理前会判断下 shouldYield,如果有更高优先级的任务,那就先执行别的。
commit 阶段不用再次遍历 fiber 树,为了优化,react 把有 effectTag 的 fiber 都放到了 effectList 队列中,遍历更新即可。
根据虚拟dom(React 元素)去生成 Fiber 树,child,sibling 和 return 三个属性构成链表。在 Fiber tree 的情况下,React不执行递归遍历。而是创建一个单链表,并执行父级优先、深度优先的遍历
双缓存
在 React 中最多会同时存在两棵 Fiber 树。当前屏幕上显示内容对应的 Fiber 树称为 current Fiber 树,正在内存中构建的 Fiber 树称为 workInProgress Fiber 树。每次状态更新都会产生新的 workInProgress Fiber 树,通过 current 与 workInProgress 的替换,完成 DOM 更新。
在构建 workInProgress Fiber 树时会尝试复用 current Fiber 树中已有的 Fiber 节点内的属性。
Fiber 如何工作
- 为不同类型的任务分配不同的优先级
- 暂停、恢复任务
- 取消不需要的任务
- 重用之前完成的任务
组件更新流程
一个 React 组件的渲染主要经历两个阶段:
- render:用新的数据生成一棵新的树,然后通过 Diff 算法,遍历旧的树,快速找出需要更新的元素,放到更新队列中去,得到新的更新队列。
- commit:遍历更新队列,通过调用宿主环境的 API,实际更新渲染对应的元素。宿主环境如 DOM,Native 等。
对于调度阶段,新老架构中有不同的处理方式:
React 16 之前使用的是 Stack Reconciler(栈协调器),使用递归的方式创建虚拟 DOM,递归的过程是不能中断的。如果组件树的层级很深,递归更新组件的时间超过 16ms,用户交互就会感觉到卡顿。
React 16 及以后使用的是 Fiber Reconciler,将递归中无法中断的更新重构为迭代中的异步可中断更新过程,这样就能够更好的控制组件的渲染。
Fiber 的主要工作流程:
ReactDOM.render()
引导 React 启动或调用setState()
的时候开始创建或更新 Fiber 树。- 从根节点开始遍历 Fiber Node Tree, 并且构建 WokeInProgress Tree(reconciliation 阶段)。
- 本阶段可以暂停、终止、和重启,会导致 react 相关生命周期重复执行。
- React 会生成两棵树,一棵是代表当前状态的 current tree,一棵是待更新的 workInProgress tree。
- 遍历 current tree,重用或更新 Fiber Node 到 workInProgress tree,workInProgress tree 完成后会替换 current tree。
- 每更新一个节点,同时生成该节点对应的 Effect List。
- 为每个节点创建更新任务。
- 将创建的更新任务加入任务队列,等待调度。
- 调度由 scheduler 模块完成,其核心职责是执行回调。
- scheduler 模块实现了跨平台兼容的 requestIdleCallback。
- 每处理完一个 Fiber Node 的更新,可以中断、挂起,或恢复。
- 根据 Effect List 更新 DOM (commit 阶段)。
- React 会遍历 Effect List 将所有变更一次性更新到 DOM 上。
- 这一阶段的工作会导致用户可见的变化。因此该过程不可中断,必须一直执行直到更新完成。
任务优先级
React Fiber 任务的优先级从高到低可以分为以下几个级别:
- 同步任务(Synchronous Task):
- 同步任务是指需要立即执行的任务,如用户交互、用户事件处理等。这些任务具有最高的优先级,因为它们直接影响到用户体验。
- 批量更新任务(Batched Updates):
- 批量更新任务是指通过 React 的 setState() 函数触发的更新。React 会将多个 setState() 调用合并成一个更新批次,并在下一个帧中执行。这些任务的优先级次于同步任务,但高于其他类型的任务。
- 动画任务(Animation Task):
- 动画任务是指需要在下一个帧中执行的动画效果,如 CSS 动画、过渡效果等。这些任务具有较高的优先级,以保证动画的流畅性。
- 闲置任务(Idle Task):
- 闲置任务是指一些低优先级的后台任务,如预加载数据、缓存更新等。这些任务的优先级最低,只在系统资源完全空闲时才会执行。
SSR
服务器端渲染(SSR)是一种在将 React 应用程序发送到客户端之前在服务器上渲染它们的技术。
SSR 可以通过减少客户端需要下载和执行的 JavaScript 量来提高性能。SSR 还可以通过使搜索引擎更轻松地索引您的 React 应用程序来提高 SEO。
以下是 React 中服务器端渲染工作原理的高级概述:
初始请求:当用户向服务器发出页面请求时,服务器接收该请求并开始处理它。
组件渲染:服务器识别需要为请求的页面渲染的 React 组件。然后,它使用服务器端渲染引擎(例如 ReactDOMServer)将这些组件渲染为 HTML。
数据获取:如果组件需要来自 API 或数据库的数据,服务器会获取该数据并在渲染过程中将其传递给组件。
HTML 生成:渲染组件并获取任何必要的数据后,服务器会生成页面的完整 HTML 表示形式,包括应用程序的初始状态。
向客户端发送 HTML:服务器将生成的 HTML 发送回客户端作为对初始请求的响应。
客户端水合:当客户端收到 HTML 时,它还会下载包含 React 代码的 JavaScript 包。
然后,客户端 JavaScript 会“水化” HTML,附加事件侦听器并重新建立任何客户端状态,使页面具有交互性。