webpack提供的一個(gè)非常強(qiáng)大的功能就是code spliting(代碼切割)。
在webpack 1.x中提供了
  require.ensure([], () => {    let module = require('./page1/module');    // do something  }, 'module1')利用require.ensure這個(gè)API使得webpack單獨(dú)將這個(gè)文件打包成一個(gè)可以異步加載的chunk.
具體的套路見(jiàn)我寫(xiě)的另一篇blog: webpack分包及異步加載套路
一句話總結(jié)就是:
在輸出的runtime代碼中,包含了異步chunk的id及chunk name的映射關(guān)系。需要異步加載相應(yīng)的chunk時(shí),通過(guò)生成script標(biāo)簽,然后插入到DOM中完成chunk的加載。通過(guò)JSONP,runtime中定義好函數(shù),chunk加載完成后即會(huì)立即執(zhí)行這個(gè)函數(shù)。
從編譯生成后的代碼來(lái)看,webpack 1.x從chunk的加載到執(zhí)行的過(guò)程處理的比較粗糙,僅僅是通過(guò)添加script標(biāo)簽,異步加載chunk后,完成函數(shù)的執(zhí)行。
這個(gè)過(guò)程當(dāng)中,如果出現(xiàn)了chunk加載不成功時(shí),這種情況下應(yīng)該如何去容錯(cuò)呢?
在webpack2中相比于webpack1.x在這個(gè)點(diǎn)的處理上是將chunk的加載包裹在了promise當(dāng)中,那么這個(gè)過(guò)程變的可控起來(lái)。具體的webpack2實(shí)現(xiàn)套路也是本文想要去說(shuō)明的地方。
webpack提供的異步加載函數(shù)是
  /******/   // This file contains only the entry chunk./******/   // The chunk loading function for additional chunks      // runtime代碼里面只包含了入口的chunk      // 這個(gè)函數(shù)的主要作用:      // 1. 異步加載chunk      // 2. 提供對(duì)于chunk加載失敗或者處于加載中的處理      // 其中chunk加載狀態(tài)的判斷是根據(jù)installedChunks對(duì)象chunkId是數(shù)字0還是數(shù)組來(lái)進(jìn)行判斷的/******/   __webpack_require__.e = function requireEnsure(chunkId) {        // 數(shù)字0代表chunk加載成功/******/     if(installedChunks[chunkId] === 0) /******/       return Promise.resolve();/******/     // an Promise means "currently loading".        // 如果installedChunks[chunkId]為一個(gè)數(shù)組/******/     if(installedChunks[chunkId]) {          // 返回一個(gè)promise對(duì)象/******/       return installedChunks[chunkId][2];/******/     }/******/     // start chunk loading        // 通過(guò)生成script標(biāo)簽來(lái)異步加載chunk.文件名是根據(jù)接受的chunkId來(lái)確認(rèn)的/******/     var head = document.getElementsByTagName('head')[0];/******/     var script = document.createElement('script');/******/     script.type = 'text/javascript';/******/     script.charset = 'utf-8';/******/     script.async = true;        // 超時(shí)時(shí)間為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的定時(shí)器,超時(shí)后觸發(fā)onScriptComplete回調(diào)/******/     var timeout = setTimeout(onScriptComplete, 120000);        // chunk加載完畢后的回調(diào)/******/     script.onerror = script.onload = onScriptComplete;/******/     function onScriptComplete() {/******/       // avoid mem leaks in IE./******/       script.onerror = script.onload = null;          // 清空定時(shí)器/******/       clearTimeout(timeout);          // 獲取這個(gè)chunk的加載狀態(tài)          // 若為數(shù)字0,表示加載成功          // 若為一個(gè)數(shù)組, 調(diào)用數(shù)組的第2個(gè)元素(第二個(gè)元素為promise內(nèi)傳入的reject函數(shù)),使得promise捕獲拋出的錯(cuò)誤。reject(new Error('xxx'))/******/       var chunk = installedChunks[chunkId];/******/       if(chunk !== 0) {/******/         if(chunk) chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));/******/         installedChunks[chunkId] = undefined;/******/       }/******/     };                // 每次需要進(jìn)行異步加載chunk時(shí),會(huì)將這個(gè)chunk的加載狀態(tài)進(jìn)行初始化為一個(gè)數(shù)組,并以key/value的形式保存在installedChunks里        // 這個(gè)數(shù)組為[resolve, reject, promise];/******/     var promise = new Promise(function(resolve, reject) {/******/       installedChunks[chunkId] = [resolve, reject];/******/     });/******/     installedChunks[chunkId][2] = promise;/******/     head.appendChild(script);        //返回promise/******/     return promise;/******/   };            
新聞熱點(diǎn)
疑難解答
圖片精選