new Promise(function(resolve) {
__webpack_require__.e(0)
.then((function (require) {
resolve(__webpack_require__("./src/a.js"));
}).bind(null,__webpack_require__))
.catch()
}).then(function(a) {
...
})
创建 promise,这个很好理解因为这里必须是要变成 promise 给后面调用的,另外一个是创建 script 标签,导入 js 文件.
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],{
/***/ "./src/a.js":(function(module, exports, __webpack_require__) {
"use strict";
eval('...');
/***/ })
}]);
webpack_require.e(chunkId)通过建立 promise 对象来跟踪按需加载模块的加载状态,并设置超时阙值,如果加载超时就抛出js异常。如果不需要处理加载超时异常的话,就不需要这个函数和 installedChunks 对象,可以把按需加载模块当作普通模块来处理。
(function(modules) { // webpackBootstrap
// modules存储的是模块函数
// The module cache,存储的是模块对象
var installedModules = {};
// objects to store loaded and loading chunks
// 按需加载的模块的promise
var installedChunks = { 2:0 };
// The require function
// require的功能是把modules对象里的模块函数转化成模块对象,
// 即运行模块函数,模块函数会把模块的export赋值给模块对象,供其他模块调用。
function __webpack_require__(moduleId) {
// Check if module is in cache
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// 下面开始把一个模块的代码转化成一个模块对象
// Create a new module (and put it into the cache)
var module = installedModules[moduleId] = {
i: moduleId,
l: false, //是否已经加载完成
exports: {} //模块输出,几乎代表模块本身
};
// Execute the module function,即运行模块函数,打包后的每个模块都是一个函数
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// Flag the module as loaded
module.l = true;
// Return the exports of the module
return module.exports;
}
// install a JSONP callback for chunk loading
var parentJsonpFunction = window["webpackJsonp"];
window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
var moduleId, chunkId, i = 0, resolves = [], result;
// 遍历chunkIds,如果对应的模块是按需加载的模块,就把其resolve函数存起来。
for(;i < chunkIds.length; i++) {
chunkId = chunkIds[i];
if(installedChunks[chunkId]) {
// 是按需加载的模块,取出其resolve函数
resolves.push(installedChunks[chunkId][0]);
}
installedChunks[chunkId] = 0; //该chunk已经被处理了
}
//遍历moreModules把模块函数存到modules中
for(moduleId in moreModules) {
if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
modules[moduleId] = moreModules[moduleId];
}
}
// 执行resolve函数,一般是__webpack_require__函数
while(resolves.length) {
resolves.shift()();
}
//遍历moreModules把模块函数转化成模块对象
if(executeModules) {
for(i=0; i < executeModules.length; i++) {
result = __webpack_require__(__webpack_require__.s = executeModules[i]);
}
}
return result;
};
__webpack_require__.e = function requireEnsure(chunkId) {
var installedChunkData = installedChunks[chunkId];
// 模块已经被处理过(加载了模块函数并转换成了模块对象),就返回promise,调用resolve
if(installedChunkData === 0) {
return new Promise(function(resolve) { resolve(); });
}
// 模块正在被加载,返回原来的promise
// 加载完后会运行模块函数,模块函数会调用resolve改变promise的状态
if(installedChunkData) {
return installedChunkData[2];
}
// 新建promise,并把resolve,reject函数和promise都赋值给installedChunks[chunkId],以便全局访问
var promise = new Promise(function(resolve, reject) {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
installedChunkData[2] = promise;
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = __webpack_require__.p + "" + chunkId + ".bundle.js";
var timeout = setTimeout(onScriptComplete, 120000);
script.onerror = script.onload = onScriptComplete;
function onScriptComplete() {
script.onerror = script.onload = null;
clearTimeout(timeout);
var chunk = installedChunks[chunkId];
if(chunk !== 0) { //没有被处理
if(chunk) {// 是按需加载模块,即请求超时了
chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));
}
installedChunks[chunkId] = undefined;
}
}
}
})([]);
所以说这个push方法其实是被劫持了的,也就是等价于运行了webpackJsonpCallback方法。webpackJsonpCallback则会去运行installedChunks[chunkId][0],也就是promise的resolve。到此整个webpack的代码分割也就梳理的非常清楚了
定义一个promise数组,用来存储promise. 判断是否已经加载过,如果加载过,返回一个空数组的promise.all(). 如果正在加载中,则返回存储过的此文件对应的promise. 如果没加载过,先定义一个promise,然后创建script标签,加载此js,并定义成功和失败的回调 返回一个promise
判断有无加载过是通过判断installedChunks[chunkId]的值是否为0,但在script.onerror/script.onload回调函数中并没有把installedChunks[chunkId]的值置为0 promise 把 resolve 和 reject 全部存入了 installedChunks 中, 并没有在获取异步chunk成功的onload 回调中执行 resolve,那么,resolve 是什么时候被执行的呢?