首页 > 语言 > JavaScript > 正文

详解webpack2异步加载套路

2024-05-06 15:30:02
字体:
来源:转载
供稿:网友

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;/******/   };            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选