React知识点总结
前言
今天学习一下React懒加载的基本原理,React懒加载采用React.lazy
和React.Suspense
。
React.lazy的基本原理
React.lazy的使用方法
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
React.lazy
将原来的静态导入转换成了import(url)
动态导入
import(url)
返回的是一个Promise
对象,其参考实现方式如下:
function import(url) {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
const tempGlobal = "__tempModuleLoadingVariable" + Math.random().toString(32).substring(2);
script.type = "module";
script.textContent = `import * as m from "${url}"; window.${tempGlobal} = m;`;
script.onload = () => {
resolve(window[tempGlobal]);
delete window[tempGlobal];
script.remove();
};
script.onerror = () => {
reject(new Error("Failed to load module script with URL " + url));
delete window[tempGlobal];
script.remove();
};
document.documentElement.appendChild(script);
});
}
React.Suspense大概原理
React.Suspense
会捕获子组件抛出的异常,如果抛出的异常的内容是Promise
,且状态为pending
,则会展示fallback
的内容,若状态为resolved
,则会展示动态导入的组件。
React.lazy的基本原理
React.lazy
函数返回一个LazyComponent
类型的对象:
export function lazy<T, R>(ctor: () => Thenable<T, R>): LazyComponent<T> {
let lazyType = {
?typeof: REACT_LAZY_TYPE,
_ctor: ctor,
// React uses these fields to store the result.
_status: -1,
_result: null,
};
return lazyType;
}
该对象保存着ctor函数,状态以及动态导入的结果。
在对LazyComponent
对象的解析过程中,主要是调用了readLazyComponentType
函数:
// Pending = 0, Resolved = 1, Rejected = 2
export function readLazyComponentType<T>(lazyComponent: LazyComponent<T>): T {
const status = lazyComponent._status;
const result = lazyComponent._result;
switch (status) {
case Resolved: {
const Component: T = result;
return Component;
}
case Rejected: {
const error: mixed = result;
throw error;
}
case Pending: {
const thenable: Thenable<T, mixed> = result;
throw thenable;
}
default: { // lazyComponent 首次被渲染
lazyComponent._status = Pending;
const ctor = lazyComponent._ctor;
const thenable = ctor();
thenable.then(
moduleObject => {
if (lazyComponent._status === Pending) {
const defaultExport = moduleObject.default;
lazyComponent._status = Resolved;
lazyComponent._result = defaultExport;
}
},
error => {
if (lazyComponent._status === Pending) {
lazyComponent._status = Rejected;
lazyComponent._result = error;
}
},
);
// Handle synchronous thenables.
switch (lazyComponent._status) {
case Resolved:
return lazyComponent._result;
case Rejected:
throw lazyComponent._result;
}
lazyComponent._result = thenable;
throw thenable;
}
}
}
从中可以看出,初始的LazyComponent
对象状态为-1,会执行default
情况,并抛出一个pending
状态的Promise
。当该Promise
的状态变为resolved
时,会将动态导入的组件赋值给LazyComponent
对象的result
,最终将组件返回。
参考博文:
[1] 深入理解React:懒加载(lazy)实现原理
[2] [译] React 16.6 懒加载(与预加载)组件