温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

webpack2中怎么实现异步加载

发布时间:2021-06-17 15:04:13 来源:亿速云 阅读:246 作者:Leah 栏目:web开发

本篇文章为大家展示了webpack2中怎么实现异步加载,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

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('path2') .addRoute({   path: 'path2',   animate: 'zoomIn',   viewBox: '.public-path2-container',   template: __webpack_require__(5),   // 挂载controller   pageInit: function pageInit() {     var _this = this;     console.time('route async path2');     // 异步加载0.js(这个文件是webpack通过code spliting自己生成的文件名)     // 具体异步加载代码的封装见?分析     // 其中0.js包含了包含了path2这个路由下的业务代码     // __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('path2', new controller(_this.viewBox));     // 添加错误处理函数,用以捕获前面可能抛出的错误     }).catch(function (e) {       return console.log('chunk loading failed');     });   },   // 进入路由跳转之前   beforeEnter: function beforeEnter() {},   // 路由跳转前   beforeLeave: function beforeLeave() {} }) .addRoute({   path: 'path3',   viewBox: '.public-path3-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 path3');       var controller = module.default;       Router.registerCtrl('path3', new controller(_this2.viewBox));     }).catch(function (e) {       return console.log('chunk loading failed');     });   },   beforeEnter: function beforeEnter() {},   beforeLeave: function beforeLeave() {} }); Router.bootstrap();

上述内容就是webpack2中怎么实现异步加载,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI