React Fiber 异步操作
一、作用
二、纠缠异步操作
备注
requestTransitionLane()由 ReactFiberRootScheduler#requestTransitionLane 实现ensureScheduleIsScheduled由 ReactFiberRootScheduler#ensureScheduleIsScheduled 实现hasScheduledTransitionWork()由 ReactProfilerTimer#hasScheduledTransitionWork 实现clearAsyncTransitionTimer()由 ReactProfilerTimer#clearAsyncTransitionTimer 实现clearEntangledAsyncTransitionTypes()由 ReactFiberTransitionTypes#clearEntangledAsyncTransitionTypes 实现
export function entangleAsyncAction<S>(
transition: Transition,
thenable: Thenable<S>,
): Thenable<S> {
// `thenable` is the return value of the async action scope function. Create
// a combined thenable that resolves once every entangled scope function
// has finished.
//
// `thenable` 是异步操作作用域函数的返回值。
// 创建一个组合的 thenable,它会在所有相关的作用域函数完成后解析。
if (currentEntangledListeners === null) {
// There's no outer async action scope. Create a new one.
// 没有外部的异步操作作用域。创建一个新的。
const entangledListeners = (currentEntangledListeners = []);
currentEntangledPendingCount = 0;
currentEntangledLane = requestTransitionLane(transition);
const entangledThenable: Thenable<void> = {
status: 'pending',
value: undefined,
then(resolve: () => mixed) {
entangledListeners.push(resolve);
},
};
currentEntangledActionThenable = entangledThenable;
if (enableDefaultTransitionIndicator) {
needsIsomorphicIndicator = true;
// We'll check if we need a default indicator in a microtask. Ensure
// we have this scheduled even if no root is scheduled.
//
// 我们将检查是否在微任务中需要默认指示器。
// 即使没有根任务安排,也要确保已安排此任务。
ensureScheduleIsScheduled();
}
}
currentEntangledPendingCount++;
thenable.then(pingEngtangledActionScope, pingEngtangledActionScope);
return thenable;
}
// pingEng 缠绕动作范围
function pingEngtangledActionScope() {
if (--currentEntangledPendingCount === 0) {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (!hasScheduledTransitionWork()) {
// If we have received no updates since we started the entangled Actions
// that means it didn't lead to a Transition being rendered. We need to
// clear the timer so that if we start another entangled sequence we use
// the next start timer instead of appearing like we were blocked the
// whole time. We currently don't log a track for Actions that don't
// render a Transition.
//
// 如果自从我们开始纠缠的动作以来没有收到任何更新
// 那就意味着它没有导致过渡被渲染。我们需要
// 清除计时器,以便如果我们开始另一个纠缠序列时使用
// 下一个启动计时器,而不是看起来我们一直被阻塞。
// 我们目前不会为没有渲染过渡的动作记录轨迹。
clearAsyncTransitionTimer();
}
}
clearEntangledAsyncTransitionTypes();
if (pendingEntangledRoots === 0) {
stopIsomorphicDefaultIndicator();
}
if (currentEntangledListeners !== null) {
// All the actions have finished. Close the entangled async action scope
// and notify all the listeners.
//
// 所有操作都已完成。关闭纠缠的异步操作范围
// 并通知所有监听器。
if (currentEntangledActionThenable !== null) {
const fulfilledThenable: FulfilledThenable<void> =
currentEntangledActionThenable as any;
fulfilledThenable.status = 'fulfilled';
}
const listeners = currentEntangledListeners;
currentEntangledListeners = null;
currentEntangledLane = NoLane;
currentEntangledActionThenable = null;
needsIsomorphicIndicator = false;
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
listener();
}
}
}
}
三、链式可处理值
export function chainThenableValue<T>(
thenable: Thenable<T>,
result: T,
): Thenable<T> {
// Equivalent to: Promise.resolve(thenable).then(() => result), except we can
// cheat a bit since we know that that this thenable is only ever consumed
// by React.
//
// 等同于:Promise.resolve(thenable).then(() => result),只是我们可以
// 偷个小懒,因为我们知道这个 thenable 只会被 React 使用。
//
// We don't technically require promise support on the client yet, hence this
// extra code.
//
// 我们实际上还不需要客户端支持 promise,因此有这段额外代码。
const listeners = [];
const thenableWithOverride: Thenable<T> = {
status: 'pending',
value: null,
reason: null,
then(resolve: (T) => void) {
listeners.push(resolve);
},
};
thenable.then(
(value: T) => {
const fulfilledThenable: FulfilledThenable<T> =
thenableWithOverride as any;
fulfilledThenable.status = 'fulfilled';
fulfilledThenable.value = result;
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
listener(result);
}
},
error => {
const rejectedThenable: RejectedThenable<T> = thenableWithOverride as any;
rejectedThenable.status = 'rejected';
rejectedThenable.reason = error;
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
// This is a perf hack where we call the `onFulfill` ping function
// instead of `onReject`, because we know that React is the only
// consumer of these promises, and it passes the same listener to both.
// We also know that it will read the error directly off the
// `.reason` field.
//
// 这是一个性能技巧,我们调用 `onFulfill` 回调函数而不是 `onReject`,
// 因为我们知道 React 是这些 Promise 的唯一使用者,并且它会将相同的监听器传给两者。
// 我们也知道它会直接从 `.reason` 字段读取错误。
listener(undefined as any);
}
},
);
return thenableWithOverride;
}
四、查看纠缠动作 Lane
export function peekEntangledActionLane(): Lane {
return currentEntangledLane;
}
五、查看纠缠动作可等待对象
export function peekEntangledActionThenable(): Thenable<void> | null {
return currentEntangledActionThenable;
}
六、注册默认指示器
export function registerDefaultIndicator(
onDefaultTransitionIndicator: () => void | (() => void),
): void {
if (!enableDefaultTransitionIndicator) {
return;
}
if (isomorphicDefaultTransitionIndicator === undefined) {
isomorphicDefaultTransitionIndicator = onDefaultTransitionIndicator;
} else if (
isomorphicDefaultTransitionIndicator !== onDefaultTransitionIndicator
) {
isomorphicDefaultTransitionIndicator = null;
// Stop any on-going indicator since it's now ambiguous.
// 停止任何正在进行的指示器,因为现在它已经不明确了。
stopIsomorphicDefaultIndicator();
}
}
七、如果需要,启动同构默认指示器
备注
reportGlobalError()由 shared/reportGlobalError 实现
export function startIsomorphicDefaultIndicatorIfNeeded() {
if (!enableDefaultTransitionIndicator) {
return;
}
if (!needsIsomorphicIndicator) {
return;
}
if (
isomorphicDefaultTransitionIndicator != null &&
pendingIsomorphicIndicator === null
) {
try {
pendingIsomorphicIndicator =
isomorphicDefaultTransitionIndicator() || noop;
} catch (x) {
pendingIsomorphicIndicator = noop;
reportGlobalError(x);
}
}
}
八、存在持续同构指示器
export function hasOngoingIsomorphicIndicator(): boolean {
return pendingIsomorphicIndicator !== null;
}
九、保留同构指示符
// 释放同构指示器
function releaseIsomorphicIndicator() {
if (--pendingEntangledRoots === 0) {
stopIsomorphicDefaultIndicator();
}
}
// 保留同构指示符
export function retainIsomorphicIndicator(): () => void {
pendingEntangledRoots++;
return releaseIsomorphicIndicator;
}
十、标记同构指示器已处理
export function markIsomorphicIndicatorHandled(): void {
needsIsomorphicIndicator = false;
}
十一、变量
1. 当前纠缠的监听器
// If there are multiple, concurrent async actions, they are entangled. All
// transition updates that occur while the async action is still in progress
// are treated as part of the action.
//
// 如果有多个并发的异步操作,它们会相互纠缠。
// 在异步操作仍在进行时发生的所有状态更新
// 都被视为该操作的一部分。
//
// The ideal behavior would be to treat each async function as an independent
// action. However, without a mechanism like AsyncContext, we can't tell which
// action an update corresponds to. So instead, we entangle them all into one.
//
// 理想的行为是将每个异步函数视为独立的操作。
// 然而,没有像 AsyncContext 这样的机制,我们无法判断某个更新对应哪个操作。
// 因此,我们只能将它们全部纠缠在一起。
// The listeners to notify once the entangled scope completes.
// 当纠缠作用域完成时要通知的监听器。
let currentEntangledListeners: Array<() => mixed> | null = null;
// The number of pending async actions in the entangled scope.
// 当前纠缠待处理数量
let currentEntangledPendingCount: number = 0;
// The transition lane shared by all updates in the entangled scope.
// 相互作用范围内所有更新共享的过渡 Lane
let currentEntangledLane: Lane = NoLane;
// A thenable that resolves when the entangled scope completes. It does not
// resolve to a particular value because it's only used for suspending the UI
// until the async action scope has completed.
//
// 一个可等待对象,当纠缠作用域完成时会被解析。
// 它不会解析为特定值,因为它仅用于在异步操作作用域完成之前暂停用户界面。
// 当前纠缠动作可等待对象
let currentEntangledActionThenable: Thenable<void> | null = null;
2. 指示器
// Track the default indicator for every root. undefined means we haven't
// had any roots registered yet. null means there's more than one callback.
// If there's more than one callback we bailout to not supporting isomorphic
// default indicators.
//
// 跟踪每个根的默认指示器。undefined 表示我们还没有注册任何根。null 表示有多个回调。
// 如果有多个回调,我们将放弃,以不支持同构默认指示器。
let isomorphicDefaultTransitionIndicator:
| void
| null
| (() => void | (() => void)) = undefined;
// The clean up function for the currently running indicator.
// 当前正在运行的指标的清理函数。
let pendingIsomorphicIndicator: null | (() => void) = null;
// The number of roots that have pending Transitions that depend on the
// started isomorphic indicator.
//
// 具有待处理转换且依赖于已启动同构指示器的根的数量。
let pendingEntangledRoots: number = 0;
// 需要同构指示器
let needsIsomorphicIndicator: boolean = false;
十二、工具
1. 停止同构默认指示器
function stopIsomorphicDefaultIndicator() {
if (!enableDefaultTransitionIndicator) {
return;
}
if (pendingIsomorphicIndicator !== null) {
const cleanup = pendingIsomorphicIndicator;
pendingIsomorphicIndicator = null;
cleanup();
}
}