“为什么 React 16 之后大型应用交互更流畅?为什么 componentWillMount 被标记为废弃?这一切都源于 Fiber 架构的重构。”
为什么有Fiber
React 15 及之前的版本采用递归同步渲染,一旦开始便无法中断,导致:
-
复杂组件树渲染时阻塞主线程,引起动画卡顿、交互延迟(如输入框无法及时响应)。
-
无法区分任务优先级(如用户点击事件优先级应高于数据加载)。
因此,Fiber就是为了解决卡顿问题产生的一种机制。
Fiber 的核心设计
Fiber架构的核心是允许任务分片,也就是将渲染工作拆分成小的单元,可以暂停和恢复。这样React可以在处理高优先级任务时中断低优先级的渲染,提升用户体验。
Fiber 的工作流程
首先Scheduler(调度器)给每个任务赋予优先级, 其次优先级高的更新任务A,会被推入 Reconciler(协调器),VDOM 转 Fiber,然后和旧的 Fiber 进行 diff 对比决定怎样生成新的 Fiber 树 。但如果此时有新的更高优先级的更新任务B 进入 Scheduler,那么 A 就会被中断,B被推入 Reconciler,当 B 完成渲染后。新一轮的调度开始,A 是新一轮中优先级最高的,那 A 就继续推入 Reconciler 执行更新任务,重复以上的可中断、可重复 步骤,直至所有更新任务完成渲染。
// 简化的任务调度逻辑
let nextUnitOfWork = null;
function workLoop(deadline) {
let shouldYield = false;
while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork); // 处理当前Fiber节点
shouldYield = deadline.timeRemaining() < 1; // 检查剩余时间
}
requestIdleCallback(workLoop);
}
function performUnitOfWork(fiber) {
// 1. 处理当前组件(如调用 render 方法)
const elements = fiber.type(fiber.props);
reconcileChildren(fiber, elements);
// 2. 返回下一个工作单元(深度优先遍历)
if (fiber.child) return fiber.child;
let nextFiber = fiber;
while (nextFiber) {
if (nextFiber.sibling) return nextFiber.sibling;
nextFiber = nextFiber.return;
}
}
双缓存机制
React 中最多会存在两颗 Fiber树:
currentFiber:页面中显示的内容
workInProgressFiber:内存中正在重新构建的 Fiber树。
当 workInProgressFiber 在内存中构建完成后,React 会直接用它 替换掉 currentFiber,这样能快速更新 DOM。一旦 workInProgressFiber 树渲染在页面上后,它就会变成 currentFiber 树,也就是说 fiberRootNode 会指向它。
关于常见的面试题
1. Fiber 如何解决渲染阻塞问题?
将同步递归改为异步可中断的链表遍历,结合时间切片和优先级调度。
2. 双缓存机制的作用是什么?
避免渲染中途出现 UI 不一致,确保更新原子性。
3. React 生命周期如何受 Fiber 影响?
废弃 componentWillMount 等可能被多次调用的生命周期,引入 getDerivedStateFromProps 等静态方法
此外Fiber节点遍历的算法,是如何实现非递归深度优先遍历的?
function walkFiber(fiber) {
let current = fiber;
while (current) {
// 1. 处理当前节点
console.log('Processing:', current.type.name || current.type);
// 2. 优先遍历子节点
if (current.child) {
current = current.child;
continue;
}
// 3. 没有子节点则遍历兄弟节点
while (current) {
// 4. 处理兄弟节点
if (current.sibling) {
current = current.sibling;
break;
}
// 5. 回溯到父节点
current = current.return;
}
}
}
快乐的时光总是短暂的,下次见。