一、ensureRootIsScheduled
登记待调度根
ini
export function ensureRootIsScheduled(root) {
// 当前 root 就是链表尾 lastScheduledRoot 或 该 root 已经在链表中
if (root === lastScheduledRoot || root.next !== null) {
} else {
if (lastScheduledRoot === null) {
// 待调度根链表头节点
firstScheduledRoot = lastScheduledRoot = root;
} else {
// 待调度根链表尾节点
lastScheduledRoot.next = root;
lastScheduledRoot = root;
}
}
mightHavePendingSyncWork = true;
ensureScheduleIsScheduled();
}
export function ensureScheduleIsScheduled() {
if (!didScheduleMicrotask) {
// 是否已经注册了根批量调度微任务
didScheduleMicrotask = true;
scheduleImmediateRootScheduleTask();
}
}
作用
- 全局调度根链表维护 :维护一条全局单向链表 收集所有存在待更新的
FiberRoot,支持多根应用(多ReactDOM.createRoot实例)批量统一处理- 当前
root就是链表尾lastScheduledRoot或该root已经在链表中,表示这个root已经登记过待调度,无需重复入队,避免重复链表操作 - 否则把
root加入待调度链表
- 当前
- 全局标记当前存在待同步 / 并发渲染任务 ,在
flushSync、批量同步刷新逻辑中会读取该标记- 若为
false,可直接快速退出同步刷新逻辑,不用遍历调度链表 - 只要任意根新增更新,立刻置为
true,提示同步刷新逻辑需要遍历链表处理任务
- 若为
- 保证全局存在且仅存在一个处理根调度的微任务,用来批量处理链表内所有待调度根。当前没有排队的调度微任务时,才走创建逻辑
- 同步设置锁,避免并发多次进入创建分支,保证微任务全局唯一
- 创建唯一批量处理微任务,把所有根的调度计算延后到当前同步代码执行完毕后统一处理
设计意义
- 支持多
root应用 (如portals或微前端) - 合并同步多轮更新 :同步代码中连续多次
setState(循环、事件内多次更新),只会触发一次微任务,只遍历一次根链表,只创建一次Scheduler任务 - 幂等防护 :多次调用
ensureScheduleIsScheduled也只会触发一次微任务创建,是批量更新合并的关键锁
二、scheduleImmediateRootScheduleTask
负责创建批量处理根调度的异步任务,自动兼容浏览器微任务能力、规避渲染 / 提交上下文死循环,是连接同步更新登记与批量渲染调度的中间层
javascript
function scheduleImmediateRootScheduleTask() {
if (supportsMicrotasks) {
scheduleMicrotask(() => {
// 检查是否在 render/commit 中(在 Safari 中,iframe 的加载会强制刷新微任务队列)
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
// 若在渲染中,用宏任务替代(防止无限循环)
Scheduler_scheduleCallback(ImmediateSchedulerPriority, processRootScheduleInImmediateTask);
return;
}
processRootScheduleInMicrotask();
});
} else {
Scheduler_scheduleCallback(ImmediateSchedulerPriority, processRootScheduleInImmediateTask);
}
}
function processRootScheduleInImmediateTask() {
processRootScheduleInMicrotask();
}
作用
- 浏览器支持
queueMicrotask:优先走微任务批量处理- 当前主线程是否正处在
render调和阶段 或commit提交阶段 :放弃微任务执行,改用Scheduler即时优先级宏任务延后批量调度至当前渲染栈完全结束 - 否则直接执行微任务批量逻辑,同一同步周期所有更新合并一次处理,减少
Scheduler碎片任务
- 当前主线程是否正处在
- 不支持微任务 / 当前处于渲染 / 提交上下文:降级为
Scheduler即时优先级宏任务
设计意义
- 优先微任务保证批量更新粒度 :微任务在当前同步调用栈清空后、浏览器渲染前执行,同一事件循环内所有同步
setState会被完全合并,不会被页面渲染切割 - 上下文安全防护 :区分 "空闲主线程" 和 "正在渲染 / 提交" 两种场景,动态切换微 / 宏任务,从底层规避并发渲染死循环,绝不允许批量调度逻辑打断正在进行的
render /commit流程
三、processRootScheduleInMicrotask
批量消费全局待调度根链表
javascript
function processRootScheduleInMicrotask() {
didScheduleMicrotask = false; // 重置去重标志
// 默认清空 "存在待同步渲染任务" 标记,遍历所有根时再重新赋值
mightHavePendingSyncWork = false;
// 检查当前事件的 transition lane
let syncTransitionLanes = NoLanes;
// 本次用户交互事件(点击、跳转、popstate)产生的 useTransition 专属车道
if (currentEventTransitionLane !== NoLane) {
if (shouldAttemptEagerTransition()) {
// popstate等场景强制同步渲染transition,保留滚动位置
syncTransitionLanes = currentEventTransitionLane;
} else if (enableDefaultTransitionIndicator) {
// 提前刷新Default车道,区分加载指示器逻辑
syncTransitionLanes = DefaultLane;
}
}
let prev = null;
let root = firstScheduledRoot;
// 遍历所有 root,为每个 root 安排任务
while (root !== null) {
const next = root.next;
// 为当前根创建Scheduler渲染任务,返回剩余待处理车道
const nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime);
// 分支1:当前根无剩余待更新车道,从链表移除
if (nextLanes === NoLane) {
// 该 root 无待处理工作 → 从调度链表中移除
root.next = null;
// 链表操作
if (prev === null) {
firstScheduledRoot = next;
} else {
prev.next = next;
}
if (next === null) {
lastScheduledRoot = prev;
}
// 分支2:根仍有未处理更新,保留在链表中
} else {
prev = root;
// 判断是否包含同步/手势过渡车道,更新mightHavePendingSyncWork
if (syncTransitionLanes !== NoLanes ||
includesSyncLane(nextLanes) ||
(enableGestureTransition && isGestureRender(nextLanes))) {
mightHavePendingSyncWork = true;
}
}
root = next;
}
// 最后刷新同步工作
// 检查是否有 ViewTransition 正在运行
// 如果有,跳过同步刷新,等 ViewTransition 完成后再执行
if (!hasPendingCommitEffects()) {
flushSyncWorkAcrossRoots_impl(syncTransitionLanes, false);
}
if (currentEventTransitionLane !== NoLane) {
currentEventTransitionLane = NoLane;
startDefaultTransitionIndicatorIfNeeded();
}
}
作用
- 释放全局微任务锁:解锁微任务锁,允许下一轮更新重新创建调度微任务
- 初始化全局同步任务标记:清空 "存在待同步渲染任务" 标记,遍历所有根时再重新赋值
- 处理事件触发的
Transition同步渲染车道- 页面前进后退需要同步渲染
Transition,保证滚动位置不丢失,把过渡车道标记为同步执行 - 开启默认过渡指示器:提前刷新
Default优先级任务,区分普通setState和过渡加载状态,避免指示器逻辑错乱
- 页面前进后退需要同步渲染
- 遍历
firstScheduledRoot单向链表,逐个为根创建并发渲染任务- 根无剩余工作,移除链表
- 清空
root.next,标记该根脱离调度链表,清理无待更新的根、维护链表首尾指针 - 分头部 / 中间 / 尾部节点更新
firstScheduledRoot、lastScheduledRoot全局指针
- 清空
- 根仍有待更新,保留链表
- 更新
prev指针,维持链表遍历 - 判断当前根剩余车道是否包含:同步
Transition车道、同步车道、手势过渡渲染车道 - 满足任一条件则置
mightHavePendingSyncWork = true,标记全局存在同步渲染任务
- 更新
- 根无剩余工作,移除链表
- 判断是否存在未执行的被动副作用(
useEffect)、提交挂起任务- 若存在待提交副作用,跳过本次同步刷新,等待副作用执行完毕再处理同步渲染,防止时序冲突
- 批量执行同步渲染任务(同步
Transition、SyncLane手势过渡),批量遍历所有根,同步执行syncTransitionLanes标记的过渡任务、全局SyncLane同步更新,直接同步渲染DOM,不进入Scheduler异步分片
- 重置事件过渡全局变量、启动默认过渡加载指示器
- 清空本次交互过渡车道,下一次交互分配全新过渡车道
- 根据本次过渡渲染结果,判断是否展示页面加载过渡指示器
设计意义
- 锁生命周期闭环:微任务执行开头释放锁,下一次更新可正常走调度流程
- 单一微任务批量消费,极致合并更新 :同一事件循环内所有同步
setState、多根更新全部收拢到一次微任务遍历,一次性批量创建所有渲染任务,杜绝碎片化Scheduler任务,是React批量更新的底层核心 - 同步渲染后置执行:放在链表遍历完成后,避免同步渲染打断链表遍历逻辑
- 副作用时序隔离 :存在
pending副作用时暂缓同步渲染,保证commit、effect、渲染顺序规范
四、scheduleTaskForRootDuringMicrotask
不做同步渲染,只负责向 Scheduler 注册 / 复用 / 取消渲染任务
javascript
function scheduleTaskForRootDuringMicrotask(root, currentTime) {
// 1. 检查是否有 lane 饿死 → 标记过期
markStarvedLanesAsExpired(root, currentTime);
// 2. 获取下一个要处理的 lanes
// 存在待执行 useEffect 的根
const rootWithPendingPassiveEffects = getRootWithPendingPassiveEffects();
// 触发被动副作用对应的车道
const pendingPassiveEffectsLanes = getPendingPassiveEffectsLanes();
// 当前正在调和的根及其渲染车道
const workInProgressRoot = getWorkInProgressRoot();
// 当前正在调和的根的渲染车道
const workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes();
// 根存在挂起提交(视图过渡、Suspense 提交中断)
const rootHasPendingCommit =
root.cancelPendingCommit !== null || root.timeoutHandle !== noTimeout;
const nextLanes =
enableYieldingBeforePassive && root === rootWithPendingPassiveEffects
? pendingPassiveEffectsLanes
: getNextLanes(
root,
root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
rootHasPendingCommit,
);
// 获取当前根已存在的调度任务,用于后续对比优先级、取消旧任务
const existingCallbackNode = root.callbackNode;
if (nextLanes === NoLanes ||
(root === workInProgressRoot && isWorkLoopSuspendedOnData()) ||
root.cancelPendingCommit !== null
) {
// 无事可做 → 取消已存在的 callback
if (existingCallbackNode !== null) {
cancelCallback(existingCallbackNode);
}
root.callbackNode = null;
root.callbackPriority = NoLane;
return NoLane;
}
// 3. 确定优先级并调度
if (includesSyncLane(nextLanes)) {
// 同步 lanes → 不通过 Scheduler(微任务结束时会同步刷新)
if (existingCallbackNode !== null) {
cancelCallback(existingCallbackNode);
}
root.callbackPriority = SyncLane;
root.callbackNode = null;
return SyncLane;
} else {
const existingCallbackPriority = root.callbackPriority;
// 从 nextLanes 取出当前最高优先级单条车道作为任务优先级
const newCallbackPriority = getHighestPriorityLane(nextLanes);
if (
newCallbackPriority === existingCallbackPriority
) {
return newCallbackPriority;
} else {
cancelCallback(existingCallbackNode);
}
// 并发 lanes → 通过 Scheduler 调度
let schedulerPriorityLevel;
switch (lanesToEventPriority(nextLanes)) {
// Discrete/Continuous(点击、输入、滚动)
case DiscreteEventPriority:
case ContinuousEventPriority:
// 用户阻塞,优先执行
schedulerPriorityLevel = UserBlockingSchedulerPriority;
break;
case DefaultEventPriority:
schedulerPriorityLevel = NormalSchedulerPriority;
break;
case IdleEventPriority:
schedulerPriorityLevel = IdleSchedulerPriority;
break;
}
const newCallbackNode = scheduleCallback(
schedulerPriorityLevel,
performWorkOnRootViaSchedulerTask.bind(null, root),
);
root.callbackPriority = newCallbackPriority;
root.callbackNode = newCallbackNode;
return newCallbackPriority;
}
}
作用
- 标记饥饿过期车道:遍历
root.pendingLanes,对比当前时间戳,把长期得不到执行、被高优任务持续抢占的饥饿车道标记为过期expiredLanes。过期车道会被优先处理,防止低优更新永久阻塞 - 计算当前根需要处理的
nextLanes- 开启新版副作用调度,当前根有待执行
useEffect:直接使用pendingPassiveEffectsLanes,把刷副作用逻辑并入本次渲染调度,不再单独创建独立Scheduler任务 - 否则获取下一个要处理的
lanes
- 开启新版副作用调度,当前根有待执行
- 无任务(根无任何待处理更新) / 渲染挂起(当前根正在渲染,因
Suspense等待数据暂停) / 提交挂起(存在中断未完成的提交流程 - 视图过渡、媒体suspend):取消现存调度任务,清空根任务标记,返回无车道 - 车道包含同步
SyncLane,且当前不是服务端预渲染场景,保证事件处理(如click)的即时反馈- 同步渲染统一在微任务末尾,
flushSyncWorkAcrossRoots_impl同步执行,不需要交给Scheduler分片调度 - 取消旧异步任务,标记优先级为
SyncLane,callbackNode置空
- 同步渲染统一在微任务末尾,
- 异步并发:对比新旧任务优先级,决定复用、取消重建
Scheduler任务- 优先级相等:复用现有任务,直接返回,不重建
- 优先级升高:取消旧任务,创建新高优任务抢占
- 映射
Lane优先级到Scheduler调度优先级 - 创建新
Scheduler渲染宏任务,回填root.callbackNode / root.callbackPriority,返回最高优先级车道
设计意义
- 并发调度饥饿防护机制:自动识别长期得不到执行的低优车道并标记过期,保证多优先级混合更新不会出现永久阻塞,避免频繁高优交互导致列表 / 异步数据低优更新卡死
- 渲染与
useEffect副作用共用一套调度任务,减少独立碎片任务 - 同优先级多次
setState复用同一个Scheduler任务,避免频繁销毁重建 - 高优更新自动抢占:新交互高优更新取消低优旧任务,保证交互响应
- 解耦两层优先级模型 :隔离
React内部Lane车道体系与Scheduler调度优先级,便于单独调整调度分片策略
五、performWorkOnRootViaSchedulerTask
Scheduler 渲染任务的顶层入口回调,并发分片渲染的启动函数
ini
function performWorkOnRootViaSchedulerTask(root, didTimeout) {
// 全局存在未完成异步提交流程:视图过渡 View Transition、Suspense 媒体延迟提交、未收尾被动副作用队列
if (hasPendingCommitEffects()) {
root.callbackNode = null;
root.callbackPriority = NoLane;
return null;
}
const originalCallbackNode = root.callbackNode;
const didFlushPassiveEffects = flushPendingEffectsDelayed();
if (didFlushPassiveEffects) {
if (root.callbackNode !== originalCallbackNode) {
return null;
}
}
const workInProgressRoot = getWorkInProgressRoot();
const workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes();
const rootHasPendingCommit =
root.cancelPendingCommit !== null || root.timeoutHandle !== noTimeout;
const lanes = getNextLanes(
root,
root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
rootHasPendingCommit,
);
if (lanes === NoLanes) {
return null;
}
const forceSync = !disableSchedulerTimeoutInWorkLoop && didTimeout;
performWorkOnRoot(root, lanes, forceSync);
scheduleTaskForRootDuringMicrotask(root, now());
if (root.callbackNode != null && root.callbackNode === originalCallbackNode) {
return performWorkOnRootViaSchedulerTask.bind(null, root);
}
return null;
}
作用
- 存在未完成异步提交流程,清空当前根的调度任务标记,直接终止本次渲染任务
- 统一执行所有被动副作用
useEffect,若执行useEffect时内部触发高优先级setState,会取消当前低优调度任务、新建更高优任务,callbackNode发生变化,直接return终止旧渲染 - 重新计算最新待渲染车道
nextLanes,合并过期车道、过滤Suspense阻塞车道、剔除正在渲染的交错更新,无任何待处理更新则直接结束任务。因为Scheduler会把多个回调合并进同一个浏览器宏任务,宏任务执行间隙不会让出微任务队列,在调度创建任务到任务实际执行之间,同步代码可能新增setState更新,旧车道数据已失效,必须重新读取最新root.pendingLanes - 区分强制同步 / 分片并发,启动真实渲染循环
- 渲染完成后重新评估剩余更新,生成续执行任务
- 复用调度函数更新任务状态
- 返回绑定自身的函数:
Scheduler会在下一个空闲时间片自动续跑剩余渲染 - 任务被取消 / 无剩余车道:返回
null,本次渲染任务彻底结束
设计意义
- 完整可中断分片续跑体系:渲染完成后自动评估剩余更新,通过返回函数实现分片续算;单次时间片仅执行少量渲染工作,主动让出主线程
- 防低饿死机制 :检测到
Scheduler分配的时间片耗尽,当前车道已过期,必须一次性完整同步渲染,不可中断让出主线程,避免低优更新永久饥饿
六、flushSyncWorkAcrossRoots_impl
全局批量同步渲染入口,微任务末尾统一执行,专门处理同步车道 SyncLane、手势过渡、popstate 同步 Transition 这类需要同步阻塞渲染的任务
ini
function flushSyncWorkAcrossRoots_impl(
syncTransitionLanes,
onlyLegacy,
) {
if (isFlushingWork) {
return;
}
if (!mightHavePendingSyncWork) {
return;
}
let didPerformSomeWork;
isFlushingWork = true;
do {
didPerformSomeWork = false;
let root = firstScheduledRoot;
while (root !== null) {
if (onlyLegacy && (disableLegacyMode || root.tag !== LegacyRoot)) {
} else {
if (syncTransitionLanes !== NoLanes) {
const nextLanes = getNextLanesToFlushSync(root, syncTransitionLanes);
if (nextLanes !== NoLanes) {
didPerformSomeWork = true;
performSyncWorkOnRoot(root, nextLanes);
}
} else {
const workInProgressRoot = getWorkInProgressRoot();
const workInProgressRootRenderLanes =
getWorkInProgressRootRenderLanes();
const rootHasPendingCommit =
root.cancelPendingCommit !== null ||
root.timeoutHandle !== noTimeout;
const nextLanes = getNextLanes(
root,
root === workInProgressRoot
? workInProgressRootRenderLanes
: NoLanes,
rootHasPendingCommit,
);
if (
(includesSyncLane(nextLanes) ||
(enableGestureTransition && isGestureRender(nextLanes))) &&
!checkIfRootIsPrerendering(root, nextLanes)
) {
didPerformSomeWork = true;
performSyncWorkOnRoot(root, nextLanes);
}
}
}
root = root.next;
}
} while (didPerformSomeWork);
isFlushingWork = false;
}
function performSyncWorkOnRoot(root: FiberRoot, lanes: Lanes) {
const didFlushPassiveEffects = flushPendingEffects();
if (didFlushPassiveEffects) {
return null;
}
const forceSync = true;
performWorkOnRoot(root, lanes, forceSync);
}
作用
- 全局防重入锁判断 :如果已经在同步渲染中,直接
return,阻断递归重入。同步渲染过程中可能触发setState再次进入本函数,锁机制防止无限递归栈溢出,是同步渲染安全屏障 - 无同步任务直接退出
- 循环遍历全局调度根链表,批量同步渲染所有符合条件的根
- 仅处理
legacy旧根过滤 - 存在同步过渡车道
syncTransitionLanes(popstate路由跳转),需要同步渲染useTransition保证页面滚动位置不丢失:调用getNextLanesToFlushSync提取当前根绑定的同步过渡车道,存在待渲染过渡车道,调用performSyncWorkOnRoot同步阻塞渲染,标记didPerformSomeWork = true,触发外层do-while循环兜底 - 普通同步车道 / 手势过渡同步渲染:调用通用
getNextLanes计算当前根待处理车道,当车道包含同步SyncLane或手势过渡车道(拖拽、滚动等高优手势)且当前根不是服务端预渲染环境(预渲染强制并发分片,禁止阻塞主线程),同步执行performSyncWorkOnRoot,标记didPerformSomeWork = true,触发外层do-while循环兜底
- 仅处理
设计意义
- 双层循环闭环 :兜底同步渲染内部新增的同步更新,解决同步
setState嵌套闭环,一轮循环清空所有同步任务 - 同步渲染周期全局锁:全程阻止重入,保证同步渲染时序完整,杜绝递归死循环