摘要
通过对比 React 15 和 React 16 的架构差异,阐述了 React 16 中 Fiber 架构在异步渲染和优先级调度方面的原理,包括 Fiber 架构的三层含义、工作原理及双缓存技术等内容,解释了其如何提升页面加载和用户交互流畅性。
一、React 不同版本效果对比及原因
首先文章给出了 React 15.7 版本和 React 16.8 版本的两个例子,在相同操作下,React 16.8 版本比 React 15.7 版本更流畅。这是因为 React 15 每次调用this.setState会重新渲染整个组件树,在componentDidMount中调用相关方法会触发大量JS运算,占住主线程,导致页面卡顿和用户输入无响应。而 React 16 引入了Fiber架构,采用异步更新策略,把update拆分成多个小块在多个事件循环周期内完成,优先渲染高优先级更新,避免阻塞主线程。
二、React 15 架构
(一)Reconciler(协调器)
在 React 15 中,可通过this.setState、this.forceUpdate、ReactDOM.render等 API 触发更新。更新时,Reconciler会调用组件的render方法将JSX转化为虚拟DOM,对比新旧虚拟DOM找出变化部分,再通知Renderer渲染。它没有优先级和中断机制,递归对比时会锁定页面。
// 假设这是一个简单的 React 15 组件示例
class MyComponent extends React.Component {
render() {
return <div>{this.props.text}</div>;
}
}
(二)Renderer(渲染器)
React 支持跨平台,不同平台有不同的Renderer,前端最熟悉的是浏览器环境下的ReactDOM。每次更新时,Renderer在接到Reconciler通知后将变化的组件渲染到宿主环境。
(三)React 15 架构的缺点
Reconciler中的mountComponent和updateComponent方法递归更新子组件,一旦层级过深且更新时间超 16ms,用户交互就会卡顿。且Reconciler和Renderer交替工作,在更新过程中用户输入不能马上响应。
三、React 16 架构
(一)Scheduler(调度器)
React 16 新增了Scheduler。原本可以使用浏览器的requestIdleCallback,但因兼容性、调度不精确、调试困难和不支持任务优先级等问题被放弃,于是 React 实现了requestIdleCallback的polyfill也就是Scheduler,它除了空闲时触发回调功能外,还提供多种调度优先级。
// 简单示意 Scheduler 可能的使用逻辑
Scheduler.scheduleTask(() => {
console.log('执行一个高优任务');
}, 'high');
(二)Reconciler(协调器)
React 16 的Reconciler将更新工作从递归变为可中断的循环过程,每次循环调用shouldYield判断是否有剩余时间。并且Reconciler与Renderer不再交替工作,Reconciler会为变化的虚拟DOM打标记,所有工作在内存中进行,全部完成后才交给Renderer。
(三)Renderer(渲染器)
Renderer根据Reconciler为虚拟DOM打的标记同步执行对应的DOM操作。
四、Fiber 架构
(一)Fiber 的起源
React 15 及以前Reconciler采用递归创建虚拟DOM且不能中断,组件树层级深时会卡顿,为解决此问题,将递归更新重构为异步可中断更新,Fiber架构应运而生。
(二)Fiber 的含义
- 作为架构:React 15 的
Reconciler是stack Reconciler(递归方式),React 16 的Reconciler基于Fiber节点实现,称为Fiber Reconciler。 - 作为静态的数据结构:每个
Fiber节点对应一个React element,保存组件类型、DOM节点等信息。 - 作为动态的工作单元:保存本次更新中组件改变的状态、要执行的工作等信息。
Fiber节点包含很多属性,可按三层含义分类。
// Fiber 节点的示例结构
function FiberNode(tag, pendingProps, key, mode) {
// 各种属性的定义
}
(三)Fiber 的工作原理
- 双缓存:React 中最多同时存在两棵
Fiber树,当前屏幕显示内容对应的是current Fiber树,正在构建的是workInProgress Fiber树,它们通过alternate属性连接,通过current指针切换。 - mount 时:首次执行
ReactDOM.render创建fiberRoot和rootFiber,fiberRoot是整个应用根节点,rootFiber是组件树根节点。在render阶段构建workInProgress Fiber树并复用已有属性,commit阶段渲染到页面后,workInProgress Fiber树变为current Fiber树。 - update 时:状态改变时开启新的
render阶段构建新的workInProgress Fiber树,复用current Fiber树节点数据,构建完成后在commit阶段渲染到页面并成为新的current Fiber树。
五、总结
React 16 引入的Scheduler与Fiber架构协同工作,Scheduler协调任务时间线,Fiber重新实现核心算法使渲染异步化,具备暂停、恢复和优先级调度能力,实现异步渲染和优先级调度,提升页面加载和用户交互的流畅性。
