摘要
通过对比 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
重新实现核心算法使渲染异步化,具备暂停、恢复和优先级调度能力,实现异步渲染和优先级调度,提升页面加载和用户交互的流畅性。