源码版本: v17.0.1,
官方源码地址
源码调试教程
调试的源码
画图软件
上文中updateContainer 函数中提到了update和updateQueue
每次更新操作就会创建update对象(ReactDOM.render和setState), 里面记录了组件的状态的变化
export type Update<State> = {|
// TODO: Temporary field. Will remove this by storing a map of
// transition -> event time on the root.
eventTime: number,
lane: Lane,
tag: 0 | 1 | 2 | 3,
payload: any,
callback: (() => mixed) | null,
next: Update<State> | null,
|};
export function createUpdate(eventTime: number, lane: Lane): Update<*> {
const update: Update<*> = {
// 获取更新触发的时间
// 它的获取方法requestEventTime(), 其实本质就是performance.now()
eventTime,
// 计算当前节点lane(优先级)
lane,
tag: UpdateState,
// 更新的内容,比如setState接收的第一个参数
payload: null,
// 对应的回调,比如setState({}, callback )
callback: null,
// 指向下一个更新, 页面中我们可能多次触发setState
next: null,
};
return update;
}
获取更新触发的时间
也就是update对象中eventTime, 以updateContainer为例, 里面有requestEventTime
react 就是通过
requestEventTime函数来创建一个currentEventTime, 用于标识更新的任务触发的时间, 对于相同的时间的任务, 就会批量去执行
同样优先级的任务,currentEventTime数值越小, 越早被执行
export function requestEventTime() {
// RenderContext: 代表react正在计算更新
// CommitContext: 代表react正在提交更新
// react更新分了两步, render 和 commit阶段
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
// react 正在执行中, 直接返回当前的时间
return now();
}
// 如果不在 react执行过程中
if (currentEventTime !== NoTimestamp) {
// 返回上一次currentEventTime
return currentEventTime;
}
// react 更新被打断后的首次更新, 计算新的currentEventTime
currentEventTime = now();
return currentEventTime;
}

export const now =
initialTimeMs < 10000 ? Scheduler_now : () => Scheduler_now() - initialTimeMs;
当前后的更新任务时间差小于 10ms 时,直接采用上次的 Scheduler_now,这样可以抹平 10ms 内更新任务的时间差, 有利于批量更新
获取更新触发的时间
以updateContainer为例, 里面有requestUpdateLane
简要概括事件优先级:
- 离散事件(DiscreteEvent):click、keydown、focusin等,这些事件的触发不是连续的,优先级为0。
- 用户阻塞事件(UserBlockingEvent):drag、scroll、mouseover等,特点是连续触发,阻塞渲染,优先级为1。
- 连续事件(ContinuousEvent):canplay、error、audio标签的timeupdate和canplay,优先级最高,为2。
export function requestUpdateLane(fiber: Fiber): Lane {
// 根据记录下的事件的优先级,获取任务调度的优先级
const schedulerPriority = getCurrentPriorityLevel();
let lane;
if (
// TODO: Temporary. We're removing the concept of discrete updates.
(executionContext & DiscreteEventContext) !== NoContext &&
schedulerPriority === UserBlockingSchedulerPriority
) {
// 如果是用户阻塞级别的事件,则通过InputDiscreteLanePriority 计算更新的优先级 lane
lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
} else {
// 否则依据事件的优先级计算 schedulerLanePriority
const schedulerLanePriority =
schedulerPriorityToLanePriority(schedulerPriority);
if (decoupleUpdatePriorityFromScheduler) {
const currentUpdateLanePriority = getCurrentUpdateLanePriority();
}
// 根据计算得到的 schedulerLanePriority,计算更新的优先级 lane
lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);
}
return lane;
}
findUpdateLane 这个方法中,按照事件的类型,匹配不同级别的 lane,事件类型的优先级,值越高,代表优先级越高:
export const SyncLanePriority: LanePriority = 15;
export const SyncBatchedLanePriority: LanePriority = 14;
const InputDiscreteHydrationLanePriority: LanePriority = 13;
export const InputDiscreteLanePriority: LanePriority = 12;
const InputContinuousHydrationLanePriority: LanePriority = 11;
export const InputContinuousLanePriority: LanePriority = 10;
const DefaultHydrationLanePriority: LanePriority = 9;
export const DefaultLanePriority: LanePriority = 8;
const TransitionHydrationPriority: LanePriority = 7;
export const TransitionPriority: LanePriority = 6;
const RetryLanePriority: LanePriority = 5;
const SelectiveHydrationLanePriority: LanePriority = 4;
const IdleHydrationLanePriority: LanePriority = 3;
const IdleLanePriority: LanePriority = 2;
const OffscreenLanePriority: LanePriority = 1;
export const NoLanePriority: LanePriority = 0;
type SharedQueue<State> = {|
pending: Update<State> | null,
|};
export type UpdateQueue<State> = {|
baseState: State,
firstBaseUpdate: Update<State> | null,
lastBaseUpdate: Update<State> | null,
shared: SharedQueue<State>,
effects: Array<Update<State>> | null,
|};
export function enqueueUpdate<State>(fiber: Fiber, update: Update<State>) {
// 获取当前fiber身上的updateQueue对象
const updateQueue = fiber.updateQueue;
if (updateQueue === null) {
// updateQueue为空, 说明当前的fiber还没有渲染, 直接退出即可
return;
}
const sharedQueue: SharedQueue<State> = (updateQueue: any).shared;
const pending = sharedQueue.pending; // shared.pending指向该链表的最后一个update对象
if (pending === null) {
// This is the first update. Create a circular list.
// 说明是首次更新, 需要创建循环链表
update.next = update;
} else {
// 不是首次更新, 那就把update对象插入到循环链表中
update.next = pending.next;
pending.next = update;
}
sharedQueue.pending = update;
}
分析:
第一次:

第二次:

第三次:

参考文章: