webpack 按需加载原理

懒加载或者按需加载,是一种很好的优化网页或应用的方式。

使用

// print.js
console.log('The print.js module has loaded! See the network tab in dev tools...');

export default () => {
  console.log('Button Clicked: Here\'s "some text"!');
};

// index.js

button.onclick = e => import(/* webpackChunkName: "print" */ './print').then(module => {
  const print = module.default;

  print();
});

注意当调用 ES6 模块的 import() 方法(引入模块)时,必须指向模块的 .default 值,因为它才是 promise 被处理后返回的实际的 module 对象

流程与原理

webpack 按需加载流程
  1. 定义一个 promise 数组,用来存储 promise.

  2. 判断是否已经加载过,如果加载过,返回一个空数组的 promise.all().

  3. 如果正在加载中,则返回存储过的此文件对应的 promise.

  4. 如果没加载过,先定义一个 promise,然后创建 script 标签,加载此 js,并定义成功和失败的回调

  5. 返回一个 promise

创建 promise,这个很好理解因为这里必须是要变成 promise 给后面调用的,另外一个是创建 script 标签,导入 js 文件.

0.main.js

webpack_require(moduleId) 通过运行 modules 里的模块函数来得到模块对象,并保存到 installedModules 对象中。

webpack_require.e(chunkId)通过建立 promise 对象来跟踪按需加载模块的加载状态,并设置超时阙值,如果加载超时就抛出 js 异常。如果不需要处理加载超时异常的话,就不需要这个函数和 installedChunks 对象,可以把按需加载模块当作普通模块来处理。

a.js 不仅有自己模块的代码,还会去往 window["webpackJsonp"]里面把增加一个数组,chunkid 和 chunk 模块的代码

所以说这个 push 方法其实是被劫持了的,也就是等价于运行了 webpackJsonpCallback 方法。webpackJsonpCallback 则会去运行 installedChunks[chunkId][0],也就是 promise 的 resolve。到此整个 webpack 的代码分割也就梳理的非常清楚了

只看这个函数,我们可能还有一下疑问:

判断有无加载过是通过判断 installedChunks[chunkId]的值是否为 0,但在 script.onerror/script.onload 回调函数中并没有把 installedChunks[chunkId]的值置为 0 promise 把 resolve 和 reject 全部存入了 installedChunks 中, 并没有在获取异步 chunk 成功的 onload 回调中执行 resolve,那么,resolve 是什么时候被执行的呢?

最后更新于

这有帮助吗?