关于第一点,我们回忆一下之前 __webpack_require__.e 的内容,此时 chunk 还处于「加载中」的状态,也就是说对应的 installedChunks[chunkId] 的值此时为[resolve, reject, promise]。 而这里,chunk 已经加载,但 promise 还未决议,于是 webpackJsonpCallback 内部定义了一个 resolves 变量用来收集 installedChunks 上的 resolve 并执行它。`
接下来说到第二点,就要涉及几个层面的缓存了。
首先是 chunk 层面,这里有两个相关操作,操作一将 installedChunks[chunkId] 置为 0 可以让 __webpack_require__.e在第二次加载同一 chunk 时返回一个立即决议的 promise(Promise.all([]));操作二将 chunk data 添加进 window["webpackJsonp"] 数组,可以在多入口模式时,方便地拿到已加载过的 chunk 缓存。通过以下代码实现:
/*** 缓存执行部分 ***/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || []; // ... for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]); var parentJsonpFunction = oldJsonpFunction; /*** 缓存执行部分 ***/ /*** 缓存添加部分 ***/ function webpackJsonpCallback(data) { //... // 此处的 parentJsonpFunction 是 window["webpackJsonp"] 数组的原生 push if (parentJsonpFunction) parentJsonpFunction(data); //... } /*** 缓存添加部分 ***/
而在 modules 层面,chunk 中的 moreModules 被合入入口文件的modules 中,可供下一个微任务中的 __webpack_require__ 同步加载模块。
({ "./src/index.js": (function (module, exports, __webpack_require__) { console.log('Hello webpack!'); window.setTimeout(() => { __webpack_require__.e(0).then(__webpack_require__.bind(null, "./src/utils/math.js")).then(mathUtil => { console.log('1 + 2: ' + mathUtil.plus(1, 2)); }); }, 2000); }) });
__webpack_require__.e(0)返回的 promise 决议后,__webpack_require__.bind(null, "./src/utils/math.js") 可以加载到chunk携带的模块,并返回模块作为下一个微任务函数的入参,接下来就是 Webpack Loader 翻译过的其他业务代码了。
现在让我们把异步流程梳理一下:
更多Webpack的基础知识请点击下面的相关文章