假如index.js
里,有代码如下:
// 同步代码
import _ from 'lodash';
var element = document.createElement('div');
element.innerHTML = _.join(['LEE', 'YANG'], '-');
document.body.appendChild(element)
// 异步加载组件
function getComponent() {
return import(/* webpackChunkName:"lodash" */'lodash').then(({default:_}) => {
var element = document.createElement('div');
element.innerHTML = _.join(['LEE', 'YANG'], '-');
return element
})
}
getComponent().then(element => {
document.body.appendChild(element)
})
上边的同步代码
和异步代码
实现的效果是一样的,都是先引入lodash
库,然后调用它的join
方法,生成字符串,最后再挂载到页面上。既然功能一样,为什么会有两种写法呢? 为什么有了同步的,还要再写另外一种异步的代码呢?
主要是因为,第二种写法,可以实现一种懒加载的行为
当前的代码是,只要页面一运行,就会生成一个元素,加载到页面上。我们可以改造 一下index.js
代码如下:
function getComponent() {
return import(/* webpackChunkName:"lodash" */'lodash').then(({default:_}) => {
var element = document.createElement('div');
element.innerHTML = _.join(['LEE', 'YANG'], '-');
return element
})
}
document.addEventListener('click', () => {
getComponent().then(element => {
document.body.appendChild(element)
})
})
改造以后,我们运行打包命令,看下生成的代码,可以看到import
引入的异步的模块,会进行代码分割单独放入vendors~lodash.js
里,而业务逻辑代码,会被放入main.js
我们打开dist
目录下的index.html
,然后刷新页面,会发现只加载了俩个文件
为什么没有加载
vendors~lodash.js
文件呢,因为现在还没有执行到引入lodash
这一步。当我们点击页面,触发了点击事件,然后执行getComponent
方法时,开始执行import
引入lodash
,然后生成元素,并挂载到页面上。懒加载就是指 通过
import
异步的去加载模块,但是具体什么时候去加载这个模块,是不一定的,要看具体代码怎么去写,只有真正执行到import
语法的时候,对应的模块才会被载入。这就是模块懒加载的概念。
懒加载有什么好处呢?
借助
import
语法,我们可以让页面的加载速度更快。比如刚才的例子,我们刷新页面的时候,根本用不到lodash
,所以只加载main.js
就行了。lodash
这一部分的代码不会被额外的载入到页面上,所以js加载的速度就会很快,页面很快就可以展示出来。我们用框架
(Vue,React等)
写代码的时候,会有路由的概念,也就是访问不同地址的时候,展示不同的页面组件。如果页面的代码,都打包在一个文件里,然后去访问项目的时候,当我们打开首页的时候,实际上一些详情页,列表页等等都一起加载了。但是实际上,我们访问首页的时候,只需要加载首页的代码,不需要加载其他页面的代码。遇到这种情况,我们就可以把首页单独做代码分割,详情页,列表页,等页面都做代码的分割,当我们做路由切换的时候,通过这种异步组件的形式,再把对应页面的代码载入执行就可以了,这样会让每个页面的加载速度有所提升。
懒加载实际上并不是
webpack
的概念,而是ES里的一个概念,也就是ECMAScript
里面提出的一个import
这样一个实验性质的语法,所以懒加载和webpack本质上关系不大。webpack只不过是能够识别出import语法,然后对它引入的模块进行代码分割而已。
import
后边可以跟一个then
说明了,它返回的是一个Promise
类型,也就意味着,如果想要在代码里使用import
,我们必须要使用babel-polyfill
,因为在低版本浏览器下,很有可能不支持promise
ES7或者最新版本的ECMAScript标准里,还引入了一个概念,叫做异步函数
的概念,用异步函数
就可以省略掉Promise.then()
这种复杂的写法,把它变成简单的写法。改代码如下:
async function getComponent() {
const { default: _ } = await import(/* webpackChunkName:"lodash" */'lodash');
const element = document.createElement('div');
element.innerHTML = _.join(['LEE', 'YANG'], '-');
return element
}
document.addEventListener('click', () => {
getComponent().then(element => {
document.body.appendChild(element)
})
})
然后我们重新打包,运行代码,跟刚才是一样的。