跳到主要内容

React 懒加载

一、作用

二、懒

export function lazy<T>(
// ctor: () => Thenable<{default: T, ...}>,
ctor: () => Thenable<{ default: T }>,
): LazyComponent<T, Payload<T>> {
const payload: Payload<T> = {
// We use these fields to store the result.
// 我们使用这些字段来存储结果。
_status: Uninitialized,
_result: ctor,
};

const lazyType: LazyComponent<T, Payload<T>> = {
$$typeof: REACT_LAZY_TYPE,
_payload: payload,
_init: lazyInitializer,
};

if (__DEV__ && enableAsyncDebugInfo) {
// TODO: We should really track the owner here but currently ReactIOInfo
// can only contain ReactComponentInfo and not a Fiber. It's unusual to
// create a lazy inside an owner though since they should be in module scope.
//
// 待办:我们确实应该在这里跟踪所有者,但目前 ReactIOInfo 只能包含 ReactComponentInfo,
// 而不能包含 Fiber。不过在所有者内部创建一个 lazy 是不常见的,因为它们应该在模块作用域内。
const owner = null;
const ioInfo: ReactIOInfo = {
name: 'lazy',
start: -1,
end: -1,
value: null,
owner: owner,
debugStack: new Error('react-stack-top-frame'),
debugTask: console.createTask ? console.createTask('lazy()') : null,
};
payload._ioInfo = ioInfo;
// Add debug info to the lazy, but this doesn't have an await stack yet.
// That will be inferred by later usage.
// 向 lazy 添加调试信息,但它尚未有 await 堆栈。 这将通过后续使用来推断。
lazyType._debugInfo = [{ awaited: ioInfo }];
}

return lazyType;
}

常量

// 未初始化
const Uninitialized = -1;
// 待处理
const Pending = 0;
// 已解决
const Resolved = 1;
// 被拒绝
const Rejected = 2;

工具

1. 延迟初始化器

备注
  • noop() 由 [noop] 实现
function lazyInitializer<T>(payload: Payload<T>): T {
if (payload._status === Uninitialized) {
let resolveDebugValue: (call: void | T) => void = null as any;
let rejectDebugValue: (mixed) => void = null as any;
if (__DEV__ && enableAsyncDebugInfo) {
const ioInfo = payload._ioInfo;
if (ioInfo != null) {
// Mark when we first kicked off the lazy request.
// 标记我们第一次启动懒请求的时间。
ioInfo.start = ioInfo.end = performance.now();
// Stash a Promise for introspection of the value later.
// 存储一个 Promise,以便稍后查看其值。
ioInfo.value = new Promise((resolve, reject) => {
resolveDebugValue = resolve;
rejectDebugValue = reject;
});
}
}
const ctor = payload._result;
const thenable = ctor();
// Transition to the next state.
// This might throw either because it's missing or throws. If so, we treat it
// as still uninitialized and try again next time. Which is the same as what
// happens if the ctor or any wrappers processing the ctor throws. This might
// end up fixing it if the resolution was a concurrency bug.
//
// 过渡到下一个状态。
// 这可能会抛出异常,因为它可能缺失或抛出。如果是这样,我们将其视为仍未初始化,并在下次尝试
// 再次处理。这与构造函数或任何处理构造函数的封装函数抛出异常时的情况相同。如果问题是由于并发
// 错误导致的解析失败,这可能最终会修复它。
thenable.then(
moduleObject => {
if (
(payload as Payload<T>)._status === Pending ||
payload._status === Uninitialized
) {
// Transition to the next state.
// 过渡到下一个状态。
const resolved: ResolvedPayload<T> = payload as any;
resolved._status = Resolved;
resolved._result = moduleObject;
if (__DEV__ && enableAsyncDebugInfo) {
const ioInfo = payload._ioInfo;
if (ioInfo != null) {
// Mark the end time of when we resolved.
// 标记我们解决问题的结束时间。
ioInfo.end = performance.now();
// Surface the default export as the resolved "value" for debug purposes.
// 将默认导出作为解析后的“值”以便调试。
const debugValue =
moduleObject == null ? undefined : moduleObject.default;
resolveDebugValue(debugValue);
ioInfo.value.status = 'fulfilled';
ioInfo.value.value = debugValue;
}
// Make the thenable introspectable
// 使 thenable 可被检查
if (thenable.status === undefined) {
// const fulfilledThenable: FulfilledThenable<{default: T, ...}> =
const fulfilledThenable: FulfilledThenable<{ default: T }> =
thenable as any;
fulfilledThenable.status = 'fulfilled';
fulfilledThenable.value = moduleObject;
}
}
}
},
error => {
if (
(payload as Payload<T>)._status === Pending ||
payload._status === Uninitialized
) {
// Transition to the next state.
// 过渡到下一个状态。
const rejected: RejectedPayload = payload as any;
rejected._status = Rejected;
rejected._result = error;
if (__DEV__ && enableAsyncDebugInfo) {
const ioInfo = payload._ioInfo;
if (ioInfo != null) {
// Mark the end time of when we rejected.
// 标记我们拒绝的结束时间。
ioInfo.end = performance.now();
// Hide unhandled rejections.
// 隐藏未处理的拒绝。
ioInfo.value.then(noop, noop);
rejectDebugValue(error);
ioInfo.value.status = 'rejected';
ioInfo.value.reason = error;
}
// Make the thenable introspectable
// 使 thenable 可被检查
if (thenable.status === undefined) {
// const rejectedThenable: RejectedThenable<{default: T, ...}> =
const rejectedThenable: RejectedThenable<{ default: T }> =
thenable as any;
rejectedThenable.status = 'rejected';
rejectedThenable.reason = error;
}
}
}
},
);
if (__DEV__ && enableAsyncDebugInfo) {
const ioInfo = payload._ioInfo;
if (ioInfo != null) {
const displayName = thenable.displayName;
if (typeof displayName === 'string') {
ioInfo.name = displayName;
}
}
}
if (payload._status === Uninitialized) {
// In case, we're still uninitialized, then we're waiting for the thenable
// to resolve. Set it as pending in the meantime.
// 如果我们仍未初始化,那么我们正在等待 thenable 解析。与此同时,将其设置为挂起状态。
const pending: PendingPayload = payload as any;
pending._status = Pending;
pending._result = thenable;
}
}
if (payload._status === Resolved) {
const moduleObject = payload._result;
if (__DEV__) {
if (moduleObject === undefined) {
console.error(
'lazy: Expected the result of a dynamic imp' +
'ort() call. ' +
'Instead received: %s\n\nYour code should look like: \n ' +
// Break up imports to avoid accidentally parsing them as dependencies.
// 拆分导入,以避免被意外解析为依赖项。
'const MyComponent = lazy(() => imp' +
"ort('./MyComponent'))\n\n" +
'Did you accidentally put curly braces around the import?',
moduleObject,
);
}
}
if (__DEV__) {
if (!('default' in moduleObject)) {
console.error(
'lazy: Expected the result of a dynamic imp' +
'ort() call. ' +
'Instead received: %s\n\nYour code should look like: \n ' +
// Break up imports to avoid accidentally parsing them as dependencies.
// 拆分导入,以避免被意外解析为依赖项。
'const MyComponent = lazy(() => imp' +
"ort('./MyComponent'))",
moduleObject,
);
}
}
return moduleObject.default;
} else {
throw payload._result;
}
}

[noop] : /shared/noop