看起来有点长,我们一步步剖析,先从第一行和最后一行来看,整个函数将异步加载的过程封装到了 promise 中,最终导出。
接着从第二行开始,installedChunkData 从缓存中取值,显然首次加载 chunk 时此处是 undefined。接下来,installedChunkData 的 undefined 值触发了第一层 if 语句的判断条件。紧接着进行到第二层 if 语句,此时根据判断条件走入 else块,这里 if 块里的内容我们先战略跳过,else里主要有两块内容,一是 chunk 脚本加载过程,这个过程创建了一个 script 标签,使其请求 chunk所在地址并执行chunk 内容;二是初始化 promise ,并用 promis 控制 chunk 文件加载过程。
不过,我们只在这段 else 代码块中找到了 reject 的使用处,也就是在 chunk 加载异常时chunk[1](error) 的地方,但并没发现更重要的 resolve的使用地点,仅仅是把 resolve 挂在了缓存上(installedChunks[chunkId] = [resolve, reject])。
这里的 chunk 文件加载下来会发生什么呢?让我们打开dist/0.js一探究竟:
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0], {
"./src/utils/math.js":
(function (module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */
__webpack_require__.d(__webpack_exports__, "plus", function () {
return plus;
});
const plus = (a, b) => {
return a + b;
};
})
}]);
我们发现了:
久违的 ./src/utils/math.js 模块
window["webpackJsonp"] 数组的使用地点
这段代码开始执行,把异步加载相关的 chunk id 与模块传给push 函数。而前面已经提到过,window["webpackJsonp"]数组的 push 函数已被重写为 webpackJsonpCallback 函数,它的定义位置在 webpackBootstrap 中:
function webpackJsonpCallback(data) {
var chunkIds = data[0];
var moreModules = data[1];
// then flag all "chunkIds" as loaded and fire callback
var moduleId, chunkId, i = 0, resolves = [];
// 将 chunk 标记为已加载
for(;i < chunkIds.length; i++) {
chunkId = chunkIds[i];
if(installedChunks[chunkId]) {
resolves.push(installedChunks[chunkId][0]);
}
installedChunks[chunkId] = 0;
}
// 把 "moreModules" 加到 webpackBootstrap 中的 modules 闭包变量中。
for(moduleId in moreModules) {
if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
modules[moduleId] = moreModules[moduleId];
}
}
// parentJsonpFunction 是 window["webpackJsonp"] 的原生 push
// 将 data 加入全局数组,缓存 chunk 内容
if(parentJsonpFunction) parentJsonpFunction(data);
// 执行 resolve 后,加载 chunk 的 promise 状态变为 resolved,then 内的函数开始执行。
while(resolves.length) {
resolves.shift()();
}
};
走进这个函数中,意味着异步加载的 chunk 内容已经拿到,这个时候我们要完成两件事,一是让依赖这次异步加载结果的模块继续执行,二是缓存加载结果。










