国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

詳解webpack2異步加載套路

2019-11-19 12:56:43
字體:
來源:轉載
供稿:網友

webpack提供的一個非常強大的功能就是code spliting(代碼切割)。

在webpack 1.x中提供了

  require.ensure([], () => {    let module = require('./page1/module');    // do something  }, 'module1')

利用require.ensure這個API使得webpack單獨將這個文件打包成一個可以異步加載的chunk.

具體的套路見我寫的另一篇blog: webpack分包及異步加載套路

一句話總結就是:

在輸出的runtime代碼中,包含了異步chunk的id及chunk name的映射關系。需要異步加載相應的chunk時,通過生成script標簽,然后插入到DOM中完成chunk的加載。通過JSONP,runtime中定義好函數,chunk加載完成后即會立即執行這個函數。

從編譯生成后的代碼來看,webpack 1.x從chunk的加載到執行的過程處理的比較粗糙,僅僅是通過添加script標簽,異步加載chunk后,完成函數的執行。

這個過程當中,如果出現了chunk加載不成功時,這種情況下應該如何去容錯呢?

在webpack2中相比于webpack1.x在這個點的處理上是將chunk的加載包裹在了promise當中,那么這個過程變的可控起來。具體的webpack2實現套路也是本文想要去說明的地方。

webpack提供的異步加載函數是

  /******/   // This file contains only the entry chunk./******/   // The chunk loading function for additional chunks      // runtime代碼里面只包含了入口的chunk      // 這個函數的主要作用:      // 1. 異步加載chunk      // 2. 提供對于chunk加載失敗或者處于加載中的處理      // 其中chunk加載狀態的判斷是根據installedChunks對象chunkId是數字0還是數組來進行判斷的/******/   __webpack_require__.e = function requireEnsure(chunkId) {        // 數字0代表chunk加載成功/******/     if(installedChunks[chunkId] === 0) /******/       return Promise.resolve();/******/     // an Promise means "currently loading".        // 如果installedChunks[chunkId]為一個數組/******/     if(installedChunks[chunkId]) {          // 返回一個promise對象/******/       return installedChunks[chunkId][2];/******/     }/******/     // start chunk loading        // 通過生成script標簽來異步加載chunk.文件名是根據接受的chunkId來確認的/******/     var head = document.getElementsByTagName('head')[0];/******/     var script = document.createElement('script');/******/     script.type = 'text/javascript';/******/     script.charset = 'utf-8';/******/     script.async = true;        // 超時時間為120s/******/     script.timeout = 120000;/******/     if (__webpack_require__.nc) {/******/       script.setAttribute("nonce", __webpack_require__.nc);/******/     }        // 需要加載的文件名/******/     script.src = __webpack_require__.p + "js/register/" + ({"2":"index"}[chunkId]||chunkId) + ".js";        // 120s的定時器,超時后觸發onScriptComplete回調/******/     var timeout = setTimeout(onScriptComplete, 120000);        // chunk加載完畢后的回調/******/     script.onerror = script.onload = onScriptComplete;/******/     function onScriptComplete() {/******/       // avoid mem leaks in IE./******/       script.onerror = script.onload = null;          // 清空定時器/******/       clearTimeout(timeout);          // 獲取這個chunk的加載狀態          // 若為數字0,表示加載成功          // 若為一個數組, 調用數組的第2個元素(第二個元素為promise內傳入的reject函數),使得promise捕獲拋出的錯誤。reject(new Error('xxx'))/******/       var chunk = installedChunks[chunkId];/******/       if(chunk !== 0) {/******/         if(chunk) chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));/******/         installedChunks[chunkId] = undefined;/******/       }/******/     };                // 每次需要進行異步加載chunk時,會將這個chunk的加載狀態進行初始化為一個數組,并以key/value的形式保存在installedChunks里        // 這個數組為[resolve, reject, promise];/******/     var promise = new Promise(function(resolve, reject) {/******/       installedChunks[chunkId] = [resolve, reject];/******/     });/******/     installedChunks[chunkId][2] = promise;/******/     head.appendChild(script);        //返回promise/******/     return promise;/******/   };

我們再來看看路由配置文件編譯后生成的代碼index.js, 特別注意下__webpack_require__.e這個異步加載函數:

Router.home('path1').addRoute({  path: 'path1',  animate: 'zoomIn',  viewBox: '.public-path1-container',  template: __webpack_require__(5),  // 掛載controller  pageInit: function pageInit() {    var _this = this;    console.time('route async path1');    // 異步加載0.js(這個文件是webpack通過code spliting自己生成的文件名)    // 具體異步加載代碼的封裝見?分析    // 其中0.js包含了包含了path1這個路由下的業務代碼    // __webpack_require__.e(0) 起的作用僅為加載chunk以及提供對于chunk加載失敗錯誤的拋出    // 具體的業務代碼的觸發是通過__webpack_require_e(0).then(__webpack_require__.bind(null, 8)).then(function(module) { ... })進行觸發    // __webpack_require__.bind(null, 8) 返回的是module[8]暴露出來的module    // 這段代碼執行時,首先初始化一個module對象    // module = {    //    i: moduleId, // 模塊id    //    l: false,   // 加載狀態    //    exports: {}  // 需要暴露的對象    //  }    // 通過異步加載的chunk最后暴露出來的對象是作為了module.exports.default屬性    // 因此在第二個方法中傳入的對象的default屬性才是你模塊8真正所暴露的對象    __webpack_require__.e/* import() */(0).then(__webpack_require__.bind(null, 8)).then(function (module) {      var controller = module.default;      Router.registerCtrl('path1', new controller(_this.viewBox));    // 添加錯誤處理函數,用以捕獲前面可能拋出的錯誤    }).catch(function (e) {      return console.log('chunk loading failed');    });  },  // 進入路由跳轉之前  beforeEnter: function beforeEnter() {},  // 路由跳轉前  beforeLeave: function beforeLeave() {}}).addRoute({  path: 'path2',  viewBox: '.public-path2-container',  animate: 'zoomIn',  template: __webpack_require__(6),  pageInit: function pageInit() {    var _this2 = this;    __webpack_require__.e/* import() */(1).then(__webpack_require__.bind(null, 9)).then(function (module) {      console.time('route async path2');      var controller = module.default;      Router.registerCtrl('path2', new controller(_this2.viewBox));    }).catch(function (e) {      return console.log('chunk loading failed');    });  },  beforeEnter: function beforeEnter() {},  beforeLeave: function beforeLeave() {}});Router.bootstrap();

總結一下就是:

webpack2相比于webpack1.x將異步加載chunk的過程封裝在了promise當中,如果chunk加載超時或者失敗會拋出錯誤,這時我們可以針對拋出的錯誤做相應的錯誤處理。

此外還應該注意下,webpack2異步加載chunk是基于原生的promise。如果部分環境暫時還不支持原生promise時需要提供polyfill。另外就是require.ensure可以接受第三個參數用以給chunk命名,但是import這個API沒有提供這個方法

更多的細節大家可以運行demo看下編譯后的代碼

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 中卫市| 文安县| 福贡县| 枞阳县| 屏东市| 上杭县| 五家渠市| 平山县| 合川市| 寻乌县| 德阳市| 延庆县| 凌海市| 咸宁市| 固镇县| 库尔勒市| 霍州市| 德令哈市| 萨迦县| 永和县| 巢湖市| 永川市| 庄浪县| 石屏县| 缙云县| 威信县| 嘉荫县| 江津市| 郑州市| 哈密市| 象州县| 佛山市| 民丰县| 韶关市| 临泉县| 中山市| 甘洛县| 五家渠市| 张家港市| 汉阴县| 通道|