在性能优化中,有一块很重要的部分 -- 网络性能优化(自动化按需加载)。
什么是自动化按需加载呢?在应用加载的过程中,我们不会将所有的资源一次性加载到前端;而是选择在切换页面/功能时,再加载其相关的资源。
如何在 React 中实现按需加载?
- 使用 Webpack 提供的
import
API,实现模块按需切割加载的功能。 - 使用
react-loadable
库实现 React 异步加载。
代码分割
打包
打包是一个将文件引入并合并到一个单独文件的过程,最终形成一个 “bundle”。接着在页面上引入该 bundle,整个应用即可一次性加载。
- App 文件:
// app.js
import { add } from './math.js';
console.log(add(16, 26)); // 42
// math.js
export function add(a, b) {
return a + b;
}
- 打包后文件:
function add(a, b) {
return a + b;
}
console.log(add(16, 26)); // 42
代码分割
随着应用迭代/完善,你的代码包也将随之增长,尤其是在整合了体积巨大的第三方库的情况下;此时,需要思考如何避免因体积过大而导致加载时间过长?
为了避免搞出大体积的代码包,在前期就思考代码分割是个不错的选择。代码分割能够提供“Lazy Loading (懒加载)” -- 只加载当前用户所需要的内容,这可以显著地提高应用性能。尽管并没有减少应用整体的代码体积,但可以避免加载用户永远不需要的代码,并在初始加载的时候减少所需加载的代码量。
import()
引入代码分割的最佳方式是通过动态 import()
语法。
- 使用之前:
import { add } from './math';
console.log(add(16, 26));
- 使用之后:
import('./math').then((math) => {
console.log(math.add(16, 26));
});
当 Webpack
解析到该语法时,会自动进行代码分割。如果你使用 Create React App
,该功能已开箱即用,你可以立刻使用该特性。Next.js
也已支持该特性而无需进行配置。
React Loadable
React Loadable
是一个很小的库,Loadable
是一个高阶组件用来轻易地在组件层面拆分 bundle。
安装
yarn add react-loadable
Loadable
的用法很简单。你仅仅要做的就是把要加载的组件和当你加载组件时的 Loading
组件传入一个方法中。
import Loadable from 'react-loadable';
import Loading from './my-loading-component';
const LoadableComponent = Loadable({
loader: () => import('./my-component'),
loading: Loading,
});
const App = () => {
return <LoadableComponent />;
};
export default App;
实战
我们在之前的项目基础上,添加按需加载。可以看到,在之前的项目中切换不同的 Tab,Network 的资源加载是不会新增,也就是说所有的资源在一开始都加载进来了。
对于组件的代码是无需改动的,我们只需在路由中配置按需加载。
首先引入 Loadable
,将静态导入改造为动态导入(() => import('./pages/xxx')
),最后返回高级函数(Loadable
)处理后的组件。
// App.js
import Loadable from 'react-loadable';
const routers = [
{
name: 'Form',
path: '/form',
loader: () => import('./pages/form'),
},
{
name: 'DynamicForm',
path: '/dynamic-form',
loader: () => import('./pages/dynamicForm'),
},
{
name: 'Multiple Request',
path: '/multiple-request',
loader: () => import('./pages/multipleRequest'),
},
// ...
];
function Loading() {
return <div>Loading...</div>;
}
{
routers.map(({ path, loader }) => {
const Component = Loadable({
loader,
loading: Loading,
});
return (
<Route key={path} path={path}>
<Component />
</Route>
);
});
}
效果
切换项目 Tab 时,Network 中加载了新的文件,这个文件就是 Tab 页相关的资源。
借助 chrome 的开发者工具,我们调慢网速来看一下 loading
状态。loading
显示正常 OK。
【不知道如何用 chrome 开发者工具 调整网速的小伙伴,看这里 ⬇️】
代码
完整项目代码,看这里
参考资料
- React 顶层 API:zh-hans.reactjs.org/docs/react-…
- 用于数据获取的 Suspense(试验阶段):zh-hans.reactjs.org/docs/concur…
- 代码分割:zh-hans.reactjs.org/docs/code-s…
- react-loadable:github.com/jamiebuilds…