戳上方蓝字关注我们吧
钟志,2013年加入去哪儿网技术团队,目前在大住宿事业部,技术委员会委员,大前端负责人。个人对移动端技术、工程化有浓厚兴趣。
前言
为了让网站加载更快,通常会将前端代码打包。React 在16.6提供 React.lazy 和 Suspense 打包优化方案,本文将介绍 React 代码打包和懒加载相关的技术。
React 16.6 引入了一些新特性,在 React 组件上使用这些新特性只需要用少量代码就能完成强大的功能。 React.lazy 和 Suspense 是其中的两个新特性,它们让 React 组件的代码拆分和懒加载变得非常简单。 本文重点介绍这两个新特性如何在 React 应用程序中使用,以及它们为 React 开发人员提供的新潜力。
为什么需要拆分代码
在过去的几年中,前端开发发生了很大的变化,随着一些新技术(如 ES6 模块化、Babel 转换器、Webpack 打包工具)的出现,现在可以用完全模块化的方式来开发 JavaScript 应用。 通常,每个模块都被导入并合并到一个名为 bundle 的单个文件中,然后 bundle 被包括在一个网页上以加载整个应用程序。然而,随着应用程序的增长,包大小开始变得太大,从而开始影响页面加载时间。 像 Webpack 和 Browserify 这样的打包工具提供了 code splitting 对代码拆分的支持,它包括将代码拆分为不同的 bundle ,这些 bundle 可以懒加载,而不是一次全部加载,从而提高了应用程序的性能。
利用import()异步加载
拆分代码的主要方式之一是利用 import() 语法动态导入,该语法还只是一个提议,这个提议为 ES 模块增加了一个新特性,允许我们异步地定义代码依赖。 在不支持 Promise 的老版本浏览器中,需要在网页中增加一个 es6-Promise 的 polyfill。 Webpack 根据 ES2015 loader 规范实现了用于动态加载的 import() 方法,这个功能可以实现懒加载代码,并且使用了 Promise 式的回调,获取加载的包。 在代码中所有被 import() 的模块,都将打成一个单独的包,放在 chunk 存储的目录下。在浏览器运行到这一行代码时,就会自动请求这个资源,实现异步加载。
import(/* webpackChunkName: "moment" */ 'moment')
.then(({ default: moment }) => {
const tomorrow = moment().startOf('day').add(1, 'day');
return tomorrow.format('LLL');
})
.catch(error => console.error('载入模块时发生错误'))
当 Webpack 遇到 import() 语法时,它会动态创建一个名称为 moment 的包。 可以看到,import() 的语法十分简单,该函数只接收一个参数,就是引用包的地址,这个地址与 ES6 的 import 以及 CommonJS 的 Require 语法用到的地址完全一致,可以实现无缝切换,且使用了 Promise 的封装,开发起来感觉十分自在。
异步加载React组件
下面的代码会一次性全部发送到浏览器:
import Description from './Description';
function App() {
return (
<div>
<h1>My Movie</h1>
<Description />
</div>
);
}
接下来将用这段代码改造成 React 异步组件:
const LoadDescription = () =>