关于javascript:webpack源码分析1

37次阅读

共计 19250 个字符,预计需要花费 49 分钟才能阅读完成。

1、打包后文件剖析


(function (modules) { // webpackBootstrap
  // The module cache
  // 缓存加载的模块
  var installedModules = {};


  // The require function
  // 上面的这个办法就是 webpack 当中自定义的,它的核心作用就是返回模块的 exports
  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,执行的是传进来的对应键值函数,执行之后会把后果挂载到 module.export 身上
    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;
  }


  // expose the modules object (__webpack_modules__)
  __webpack_require__.m = modules;


  // expose the module cache
  __webpack_require__.c = installedModules;


  // define getter function for harmony exports
  __webpack_require__.d = function (exports, name, getter) {if (!__webpack_require__.o(exports, name)) {Object.defineProperty(exports, name, { enumerable: true, get: getter});
    }
  };


  // define __esModule on exports
  __webpack_require__.r = function (exports) {if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module'});
    }
    Object.defineProperty(exports, '__esModule', { value: true});
  };


  // create a fake namespace object
  // mode & 1: value is a module id, require it
  // mode & 2: merge all properties of value into the ns
  // mode & 4: return value when already ns object
  // mode & 8|1: behave like require
  __webpack_require__.t = function (value, mode) {if (mode & 1) value = __webpack_require__(value);
    if (mode & 8) return value;
    if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
    var ns = Object.create(null);
    __webpack_require__.r(ns);
    Object.defineProperty(ns, 'default', { enumerable: true, value: value});
    if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) {return value[key]; }.bind(null, key));
    return ns;
  };


  // getDefaultExport function for compatibility with non-harmony modules
  __webpack_require__.n = function (module) {
    var getter = module && module.__esModule ?
      function getDefault() { return module['default']; } :
      function getModuleExports() { return module;};
    __webpack_require__.d(getter, 'a', getter);
    return getter;
  };


  // Object.prototype.hasOwnProperty.call
  __webpack_require__.o = function (object, property) {return Object.prototype.hasOwnProperty.call(object, property); };


  // __webpack_public_path__
  __webpack_require__.p = "";


  // Load entry module and return exports
  return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
  /************************************************************************/
  ({
    "./src/index.js":
      /*! no static exports found */
      (function (module, exports) {console.log('index.js 内容')
        module.exports = '入口文件导出内容'
      })
  });

/**

  • 01 打包后的文件就是一个函数自调用,以后函数调用时传入一个对象
  • 02 这个对象咱们为了不便将之称为是模块定义,它就是一个键值对
  • 03 这个键名就是以后被加载模块的文件名与某个目录的拼接()
  • 04 这个键值就是一个函数,和 node.js 里的模块加载有一些相似,会将被加载模块中的内容包裹于一个函数中
  • 05 这个函数在未来某个工夫点上会被调用,同时会接管到肯定的参数,利用这些参数就能够实现模块的加载操作
    *
  • 06 针对于上述的代码就相当于是将 {}(模块定义)传递给了 modules
    */

初始化了一个环境,匿名函数自调用__webpack_require__,模块 ID 表明所选模块,最终返回一个解析了所有依赖关系的模块

2、性能函数剖析


(function (modules) { // webpackBootstrap
  // The module cache
  // 定义对象用于缓存已加载过的模块
  var installedModules = {};


  // The require function
  // webpack 自定义的一个加载办法,外围性能就是返回被加载模块中导出的内容(具体外部是如何实现的,后续再剖析)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;
  }


  // expose the modules object (__webpack_modules__)
  // 将模块定义保留一份,通过 m 属性挂载到自定义的办法身上
  __webpack_require__.m = modules;


  // expose the module cache
  __webpack_require__.c = installedModules;


  // Object.prototype.hasOwnProperty.call
  // 判断被传入的对象 obj 身上是否具备指定的属性 **** , 如果有则返回 true
  __webpack_require__.o = function (object, property) {return Object.prototype.hasOwnProperty.call(object, property); };


  // define getter function for harmony exports
  __webpack_require__.d = function (exports, name, getter) {
    // 如果以后 exports 身上不具备 name 属性,则条件成立
    if (!__webpack_require__.o(exports, name)) {Object.defineProperty(exports, name, { enumerable: true, get: getter});
    }
  };


  // define __esModule on exports
  __webpack_require__.r = function (exports) {
    // 上面的条件如果成立就阐明是一个  esModule
    if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {// Object.prototype.toString.call(exports)
      Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module'});
    }
    // 如果条件不成立,咱们也间接在 exports 对象的身上增加一个 __esModule 属性,它的值就是 true
    Object.defineProperty(exports, '__esModule', { value: true});
  };


  // create a fake namespace object
  // mode & 1: value is a module id, require it
  // mode & 2: merge all properties of value into the ns
  // mode & 4: return value when already ns object
  // mode & 8|1: behave like require
  __webpack_require__.t = function (value, mode) {
    // 01 调用 t 办法之后,咱们会拿到被加载模块中的内容 value
    // 02 对于 value 来说咱们可能会间接返回,也可能会解决之后再返回
    if (mode & 1) value = __webpack_require__(value);
    if (mode & 8) return value;
    if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
    var ns = Object.create(null);
    __webpack_require__.r(ns);
    Object.defineProperty(ns, 'default', { enumerable: true, value: value});
    if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) {return value[key]; }.bind(null, key));
    return ns;
  };


  // getDefaultExport function for compatibility with non-harmony modules
  __webpack_require__.n = function (module) {
    var getter = module && module.__esModule ?
      function getDefault() { return module['default']; } :
      function getModuleExports() { return module;};
    __webpack_require__.d(getter, 'a', getter);
    return getter;
  };


  // __webpack_public_path__
  __webpack_require__.p = "";


  // Load entry module and return exports
  return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
  /************************************************************************/
  ({
    "./src/index.js":
      /*! no static exports found */
      (function (module, exports, __webpack_require__) {let name = __webpack_require__(/*! ./login.js */ "./src/login.js")
        console.log('index.js 内容执行了')
        console.log(name)
      }),
    "./src/login.js":
      /*! no static exports found */
      (function (module, exports) {module.exports = '拉勾教育'})
  });

3、CommonJs 打包


({
"./src/index.js":
(function (module, exports, __webpack_require__) {let obj = __webpack_require__(/*! ./login.js */ "./src/login.js")

console.log('index.js 内容执行了')
console.log(obj.default, '---->', obj.age)



}),
"./src/login.js":
(function (module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);// 给这个模块加标记
__webpack_require__.d(__webpack_exports__, "age", function () {return age;});// 给这个模块增加 age 属性,前面的是 getter 办法

__webpack_exports__["default"] = ('zcegg');// 默认值的增加
const age = 18

})
});

采纳 esm 导出内容引入时采纳 require 办法

4、esModule 模块打包


({
"./src/index.js":
(function (module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
var _login_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./login.js */ "./src/login.js");

console.log('index.js 内容加载了')
console.log(_login_js__WEBPACK_IMPORTED_MODULE_0__["default"], '---->', _login_js__WEBPACK_IMPORTED_MODULE_0__["age"])

}),
"./src/login.js":
(function (module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, "age", function () {return age;});

__webpack_exports__["default"] = ('拉勾教育');
const age = 100

})
});

5、性能函数手写实现


(function (modules) {
  // 01 定义对象用于未来缓存被加载过的模块
  let installedModules = {}


  // 02 定义一个 __webpack_require__ 办法来替换 import require 加载操作
  function __webpack_require__(moduleId) {
    // 2-1 判断以后缓存中是否存在要被加载的模块内容,如果存在则间接返回
    if (installedModules[moduleId]) {return installedModules[moduleId].exports
    }


    // 2-2 如果以后缓存中不存在则须要咱们本人定义 {} 执行被导入的模块内容加载
    let module = installedModules[moduleId] = {
      i: moduleId,
      l: false,
      exports: {}}


    // 2-3 调用以后 moduleId 对应的函数,而后实现内容的加载
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)


    // 2-4 当上述的办法调用实现之后,咱们就能够批改 l 的值用于示意以后模块内容曾经加载实现了
    module.l = true


    // 2-5 加载工作实现之后,要将拿回来的内容返回至调用的地位
    return module.exports
  }


  // 03 定义 m 属性用于保留 modules
  __webpack_require__.m = modules


  // 04 定义 c 属性用于保留 cache
  __webpack_require__.c = installedModules


  // 05 定义 o 办法用于判断对象的身上是否存在指定的属性
  __webpack_require__.o = function (object, property) {return Object.prototype.hasOwnProperty(object, property)
  }


  // 06 定义 d 办法用于在对象的身上增加指定的属性,同时给该属性提供一个 getter
  __webpack_require__.d = function (exports, name, getter) {if (!__webpack_require__.o(exports, name)) {Object.defineProperty(exports, name, { enumerable: true, get: getter})
    }
  }


  // 07 定义 r 办法用于标识以后模块是 es6 类型
  __webpack_require__.r = function (exports) {if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {Object.defineProperty(exports, Symbol.toStringTag, { value: "Module"})
    }
    Object.defineProperty(exports, '__esModule', { value: true})
  }


  // 08 定义 n 办法,用于设置具体的 getter
  __webpack_require__.n = function (module) {
    let getter = module && module.__esModule ?
      function getDefault() { return module['default'] } :
      function getModuleExports() { return module}


    __webpack_require__.d(getter, 'a', getter)


    return getter
  }


  // 09 定义 P 属性,用于保留资源拜访门路
  __webpack_require__.p = ""


  // 10 调用 __webpack_require__ 办法执行模块导入与加载操作
  return __webpack_require__(__webpack_require__.s = './src/index.js')


})
  ({
    "./src/index.js":
      (function (module, __webpack_exports__, __webpack_require__) {


        "use strict";
        __webpack_require__.r(__webpack_exports__);
        var _login_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./login.js */ "./src/login.js");
        console.log('index.js 执行了')
        console.log(_login_js__WEBPACK_IMPORTED_MODULE_0__["default"], '<------')
        console.log(_login_js__WEBPACK_IMPORTED_MODULE_0__["age"], '<------')
      }),
    "./src/login.js":
      (function (module, __webpack_exports__, __webpack_require__) {
        "use strict";
        __webpack_require__.r(__webpack_exports__);
        __webpack_require__.d(__webpack_exports__, "age", function () {return age;});
        __webpack_exports__["default"] = ('zce 是一个帅哥');
        const age = 40
      })


  })

11、懒加载实现


let oBtn = document.getElementById('btn')


oBtn.addEventListener('click', function () {import(/*webpackChunkName: "login"*/'./login.js').then((login) => {console.log(login)
  })
})


console.log('index.js 执行了')



  ({
    "./src/index.js":
      (function (module, exports, __webpack_require__) {let oBtn = document.getElementById('btn')
        oBtn.addEventListener('click', function () {__webpack_require__.e(/*! import() | login */ "login").then(__webpack_require__.t.bind(null, /*! ./login.js */ "./src/login.js", 7)).then((login) => {console.log(login)
          })
        })
        console.log('index.js 执行了')
      })
  });

新的属性 e,t 办法

12、t 办法


  __webpack_require__.t = function (value, mode) {
    /**
     * 01 接管二个参数,一个是 value 个别用于示意被加载的模块 id,第二个值 mode 是一个二进制的数值
     * 02 t 办法外部做的第一件事件就是调用自定义的 require 办法加载 value 对应的模块导出,从新赋值给 value
     * 03 当获取到了这个 value 值之后余下的 8 4 ns 2 都是对以后的内容进行加工解决,而后返回应用
     * 04 当 mode & 8 成立是间接将 value 返回(commonJS)* 05 当 mode & 4 成立时间接将 value 返回(esModule)* 06 如果上述条件都不成立,还是要持续解决 value,定义一个  ns {}
     *  6-1 如果拿到的 value 是一个能够间接应用的内容,例如是一个字符串,将它挂载到 ns 的 default 属性上
     *  6-2 如果不是,就把这个对象的键值对一个一个赋值到 ns 上
     */
    if (mode & 1) value = __webpack_require__(value);
    if (mode & 8) return value;
    if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
    var ns = Object.create(null);
    __webpack_require__.r(ns);
    Object.defineProperty(ns, 'default', { enumerable: true, value: value});
    if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) {return value[key]; }.bind(null, key));
    return ns;
  };

// 11 定义 t 办法,用于加载指定 value 的模块内容,之后对内容进行解决再返回

 __webpack_require__.t = function (value, mode) {
    // 01 加载 value 对应的模块内容(value 个别就是模块 id)// 加载之后的内容又从新赋值给 value 变量
    if (mode & 1) {value = __webpack_require__(value)
    }


    if (mode & 8) {  // 加载了能够间接返回应用的内容
      return value
    }


    if ((mode & 4) && typeof value === 'object' && value && value.__esModule) {return value}


    // 如果 8 和 4 都没有成立则须要自定义 ns 来通过 default 属性返回内容
    let ns = Object.create(null)


    __webpack_require__.r(ns)


    Object.defineProperty(ns, 'default', { enumerable: true, value: value})


    if (mode & 2 && typeof value !== 'string') {for (var key in value) {__webpack_require__.d(ns, key, function (key) {return value[key]
        }.bind(null, key))
      }
    }


    return ns
  }

13、懒加载


(function (modules) { // webpackBootstrap
  // install a JSONP callback for chunk loading
  function webpackJsonpCallback(data) {var chunkIds = data[0];
    var moreModules = data[1];
    // add "moreModules" to the modules object,
    // then flag all "chunkIds" as loaded and fire callback
    var moduleId, chunkId, i = 0, resolves = [];
    for (; i < chunkIds.length; i++) {chunkId = chunkIds[i];
      if (Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {resolves.push(installedChunks[chunkId][0]);
      }
      installedChunks[chunkId] = 0;
    }
    for (moduleId in moreModules) {if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {modules[moduleId] = moreModules[moduleId];
      }
    }
    if (parentJsonpFunction) parentJsonpFunction(data);


    while (resolves.length) {resolves.shift()();}


  };


  // The module cache
  var installedModules = {};


  // object to store loaded and loading chunks
  // undefined = chunk not loaded, null = chunk preloaded/prefetched
  // Promise = chunk loading, 0 = chunk loaded
  var installedChunks = {"main": 0};


  // script path function
  function jsonpScriptSrc(chunkId) {return __webpack_require__.p + ""+ chunkId +".built.js"}


  // The require function
  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;
  }


  // This file contains only the entry chunk.
  // The chunk loading function for additional chunks
  __webpack_require__.e = function requireEnsure(chunkId) {var promises = [];




    // JSONP chunk loading for javascript


    var installedChunkData = installedChunks[chunkId];
    if (installedChunkData !== 0) { // 0 means "already installed".


      // a Promise means "currently loading".
      if (installedChunkData) {promises.push(installedChunkData[2]);
      } else {
        // setup Promise in chunk cache
        var promise = new Promise(function (resolve, reject) {installedChunkData = installedChunks[chunkId] = [resolve, reject];
        });
        promises.push(installedChunkData[2] = promise);


        // start chunk loading
        var script = document.createElement('script');
        var onScriptComplete;


        script.charset = 'utf-8';
        script.timeout = 120;
        if (__webpack_require__.nc) {script.setAttribute("nonce", __webpack_require__.nc);
        }
        script.src = jsonpScriptSrc(chunkId);


        // create error before stack unwound to get useful stacktrace later
        var error = new Error();
        onScriptComplete = function (event) {
          // avoid mem leaks in IE.
          script.onerror = script.onload = null;
          clearTimeout(timeout);
          var chunk = installedChunks[chunkId];
          if (chunk !== 0) {if (chunk) {var errorType = event && (event.type === 'load' ? 'missing' : event.type);
              var realSrc = event && event.target && event.target.src;
              error.message = 'Loading chunk' + chunkId + 'failed.\n(' + errorType + ':' + realSrc + ')';
              error.name = 'ChunkLoadError';
              error.type = errorType;
              error.request = realSrc;
              chunk[1](error);
            }
            installedChunks[chunkId] = undefined;
          }
        };
        var timeout = setTimeout(function () {onScriptComplete({ type: 'timeout', target: script});
        }, 120000);
        script.onerror = script.onload = onScriptComplete;
        document.head.appendChild(script);
      }
    }
    return Promise.all(promises);
  };


  // expose the modules object (__webpack_modules__)
  __webpack_require__.m = modules;


  // expose the module cache
  __webpack_require__.c = installedModules;


  // define getter function for harmony exports
  __webpack_require__.d = function (exports, name, getter) {if (!__webpack_require__.o(exports, name)) {Object.defineProperty(exports, name, { enumerable: true, get: getter});
    }
  };


  // define __esModule on exports
  __webpack_require__.r = function (exports) {if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module'});
    }
    Object.defineProperty(exports, '__esModule', { value: true});
  };


  // create a fake namespace object
  // mode & 1: value is a module id, require it
  // mode & 2: merge all properties of value into the ns
  // mode & 4: return value when already ns object
  // mode & 8|1: behave like require
  __webpack_require__.t = function (value, mode) {if (mode & 1) value = __webpack_require__(value);
    if (mode & 8) return value;
    if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
    var ns = Object.create(null);
    __webpack_require__.r(ns);
    Object.defineProperty(ns, 'default', { enumerable: true, value: value});
    if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) {return value[key]; }.bind(null, key));
    return ns;
  };


  // getDefaultExport function for compatibility with non-harmony modules
  __webpack_require__.n = function (module) {
    var getter = module && module.__esModule ?
      function getDefault() { return module['default']; } :
      function getModuleExports() { return module;};
    __webpack_require__.d(getter, 'a', getter);
    return getter;
  };


  // Object.prototype.hasOwnProperty.call
  __webpack_require__.o = function (object, property) {return Object.prototype.hasOwnProperty.call(object, property); };


  // __webpack_public_path__
  __webpack_require__.p = "";


  // on error function for async loading
  __webpack_require__.oe = function (err) {console.error(err); throw err; };


  var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
  var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);// 重写 push 办法
  jsonpArray.push = webpackJsonpCallback;
  jsonpArray = jsonpArray.slice();
  for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
  var parentJsonpFunction = oldJsonpFunction;




  // Load entry module and return exports
  return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
  /************************************************************************/
  ({
    "./src/index.js":
      (function (module, exports, __webpack_require__) {let oBtn = document.getElementById('btn')
        oBtn.addEventListener('click', function () {__webpack_require__.e(/*! import() | login */ "login").then(__webpack_require__.t.bind(null, /*! ./login.js */ "./src/login.js", 7)).then((login) => {console.log(login)
          })
        })
        console.log('index.js 执行了')
      })
  });

14、懒加载手写实现


function webpackJsonpCallback(data) {// 合并模块定义,扭转 promise 状态执行后续行为

// 获取须要动静加载的模块 id
var chunkIds = data[0];

// 获取须要被动静加载的模块依赖关系
var moreModules = data[1];

// add "moreModules" to the modules object,
// then flag all "chunkIds" as loaded and fire callback
var moduleId, chunkId, i = 0, resolves = [];

for (; i < chunkIds.length; i++) {chunkId = chunkIds[i];

if (Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {resolves.push(installedChunks[chunkId][0]);
}
installedChunks[chunkId] = 0;

}
for (moduleId in moreModules) {if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {modules[moduleId] = moreModules[moduleId];

}
}
if (parentJsonpFunction) parentJsonpFunction(data);



while (resolves.length) {resolves.shift()();}


};


// 实现 json 加载内容,利用 promise 来实现异步加载操作
__webpack_require__.e = function requireEnsure(chunkId) {var promises = [];



// JSONP chunk loading for javascript
// 获取 chunkid 对应的 chunk,是否曾经实现加载
var installedChunkData = installedChunks[chunkId];

if (installedChunkData !== 0) { // 0 means "already installed".



// a Promise means "currently loading".
if (installedChunkData) {promises.push(installedChunkData[2]);
} else {

// setup Promise in chunk cache
var promise = new Promise(function (resolve, reject) {installedChunkData = installedChunks[chunkId] = [resolve, reject];

});
promises.push(installedChunkData[2] = promise);// 下标为 2 是参考的源码



// start chunk loading
var script = document.createElement('script');

var onScriptComplete;



script.charset = 'utf-8';

script.timeout = 120;

if (__webpack_require__.nc) {script.setAttribute("nonce", __webpack_require__.nc);

}
script.src = jsonpScriptSrc(chunkId);



// create error before stack unwound to get useful stacktrace later
var error = new Error();

onScriptComplete = function (event) {

// avoid mem leaks in IE.
script.onerror = script.onload = null;

clearTimeout(timeout);
var chunk = installedChunks[chunkId];

if (chunk !== 0) {if (chunk) {var errorType = event && (event.type === 'load' ? 'missing' : event.type);

var realSrc = event && event.target && event.target.src;

error.message = 'Loading chunk' + chunkId + 'failed.\n(' + errorType + ':' + realSrc + ')';

error.name = 'ChunkLoadError';

error.type = errorType;

error.request = realSrc;

chunk[1](error);
}
installedChunks[chunkId] = undefined;

}
};
var timeout = setTimeout(function () {onScriptComplete({ type: 'timeout', target: script});

}, 120000);

script.onerror = script.onload = onScriptComplete;

document.head.appendChild(script);
}
}
return Promise.all(promises);

};

正文完
 0