React 调和阶段的中断实现机制

1. 概述

React 16 引入的新调和引擎(Fiber Reconciler)最重要的特性之一就是可中断的渲染过程。这个特性让 React 能够将渲染工作分割成多个小块,并且能够暂停和恢复渲染过程,从而提供更好的用户体验。

2. Fiber 架构

2.1 什么是 Fiber

Fiber 是 React 16 中新的协调引擎。它的主要目标是启用虚拟 DOM 的增量渲染。

  • Fiber 是一种数据结构,代表一个工作单元

  • 每个 React 元素都对应一个 Fiber 节点

  • Fiber 节点构成了一个链表树结构

2.2 Fiber 节点的结构

javascript 复制代码
type Fiber = {

// 标记不同类型的节点

tag: WorkTag,

// 节点的唯一标识

key: null | string,

// 节点的类型信息

type: any,

// 当前节点的状态

stateNode: any,

  


// Fiber 树结构

return: Fiber | null,

child: Fiber | null,

sibling: Fiber | null,

  


// 工作单元

pendingProps: any,

memoizedProps: any,

updateQueue: UpdateQueue<any> | null,

};

3. 时间切片(Time Slicing)

3.1 基本原理

时间切片的核心思想是将长任务分割成小片段,每个片段的执行时间都很短,从而不会阻塞主线程。

javascript 复制代码
const ENOUGH_TIME = 1; // 假设 1ms 就需要让出主线程

  


let deadline = 0;

  


const shouldYield = () => {

return performance.now() >= deadline;

};

  


const workLoop = (hasTimeRemaining) => {

while (nextUnitOfWork && hasTimeRemaining) {

nextUnitOfWork = performUnitOfWork(nextUnitOfWork);

if (shouldYield()) {

// 时间片到期,中断执行

break;

}

}

};

3.2 requestIdleCallback

React 使用 requestIdleCallback(在生产环境使用自己实现的调度器)来调度任务:

javascript 复制代码
requestIdleCallback((deadline) => {

// deadline.timeRemaining() 返回当前帧还剩余的时间

while (deadline.timeRemaining() > 0 && nextUnitOfWork) {

nextUnitOfWork = performUnitOfWork(nextUnitOfWork);

}

});

4. 调度优先级

4.1 优先级划分

React 的调度优先级从高到低:

  1. Immediate:立即执行的优先级

  2. UserBlocking:用户交互的优先级

  3. Normal:正常优先级

  4. Low:低优先级

  5. Idle:空闲优先级

4.2 优先级实现

javascript 复制代码
const priorityLevel = {

ImmediatePriority: 1,

UserBlockingPriority: 2,

NormalPriority: 3,

LowPriority: 4,

IdlePriority: 5

};

  


function scheduleCallback(priorityLevel, callback) {

const currentTime = getCurrentTime();

const timeout = getTimeoutForPriority(priorityLevel);

const expirationTime = currentTime + timeout;

  


const newTask = {

callback,

priorityLevel,

expirationTime,

// ...

};

  


// 将任务加入优先级队列

addTaskToQueue(newTask);

}

5. 中断机制的实现

5.1 工作循环

javascript 复制代码
function workLoopConcurrent() {

while (workInProgress !== null && !shouldYield()) {

workInProgress = performUnitOfWork(workInProgress);

}

}

  


function performUnitOfWork(unitOfWork) {

// 1. 执行当前工作单元

const current = unitOfWork.alternate;

let next = beginWork(current, unitOfWork, renderExpirationTime);

  


// 2. 完成当前工作单元

if (next === null) {

next = completeUnitOfWork(unitOfWork);

}

  


return next;

}

5.2 中断和恢复

当时间片用完时,React 会:

  1. 保存当前工作进度

  2. 让出主线程

  3. 等待下一个时间片

  4. 从上次中断的地方继续执行

javascript 复制代码
function renderRoot(root, isYieldy) {

do {

try {

workLoop(isYieldy);

break;

} catch (thrownValue) {

// 错误处理

}

} while (true);

  


if (isYieldy && workInProgress !== null) {

// 还有工作要做,但时间片已用完

return RootIncomplete;

} else {

// 所有工作完成

return RootCompleted;

}

}

6. 总结

React 的可中断渲染机制是通过以下几个关键点实现的:

  1. Fiber 架构提供了可分割的最小工作单元

  2. 时间切片机制确保了渲染过程不会长期占用主线程

  3. 优先级调度系统保证了重要的更新能够优先执行

  4. 完善的中断和恢复机制确保了渲染过程的连续性

这种机制让 React 能够在保持响应性的同时,处理复杂的渲染任务,从而提供更好的用户体验。

相关推荐
sunbyte2 小时前
Three.js + React 实战系列 - 职业经历区实现解析 Experience 组件✨(互动动作 + 3D 角色 + 点击切换动画)
javascript·react.js·3d
Python私教4 小时前
使用FastAPI和React以及MongoDB构建全栈Web应用05 FastAPI快速入门
前端·react.js·fastapi
海绵不是宝宝8175 小时前
React+Springboot项目部署ESC服务器
前端·react.js·前端框架
ZHOU_WUYI6 小时前
React 实现 JWT 登录验证的最小可运行示例
前端·react.js·前端框架
Lysun0017 小时前
electron 结合 react(cra创建的) 创建桌面应用和打包桌面应用
javascript·react.js·electron
Python私教8 小时前
全栈开发实战:FastAPI + React + MongoDB 构建现代Web应用
前端·react.js·fastapi
进取星辰1 天前
21、魔法传送阵——React 19 文件上传优化
前端·react.js·前端框架
恋猫de小郭1 天前
React Native 前瞻式重大更新 Skia & WebGPU & ThreeJS,未来可期
android·javascript·flutter·react native·react.js·ios
蓉妹妹1 天前
React+Taro选择日期组件封装
前端·react.js·前端框架
学渣y1 天前
React文档-State数据扁平化
前端·javascript·react.js