Webpack 打包后代码执行时机分析与优化

更新日期: 2019-08-01阅读: 2.6k标签: 优化

代码执行时机将决定着是否能够正常执行,当依赖文件没加载完成就开始执行、使用对应模块,那么将会导致执行异常。这在“ 存在资源加载失败时,加载重试影响原来文件的执行顺序 ”的场景下尤为常见。

webpack 构建除了进行模块依赖管理,实际上,也天然地管理了 entry 与 chunk 多文件的执行时机,但缺少了对 external 文件管理,当 external 文件加载失败或未完成时,执行、使用对应模块同样将导致异常。为此, wait-external-webpack-plugin 应运而生,以 webpack 插件的形式,补充 external 的执行管理。本文将进行简要说明。


一、单文件

将 webpack 打包后的代码进行简化,其实就是一个立即调用函数;传入“模块”,使用 webpack_require 进行调用。在单文件下,文件加载后将立即执行业务逻辑。

(function(modules) { // webpackBootstrap
     function __webpack_require__(moduleId) {
        // ...
	// 执行模块代码
	modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
     }
     // 引用入口
     return __webpack_require__(__webpack_require__.s = "./src/entryB.js");
 })({
    "./entryB.js": (function(module, __webpack_exports__, __webpack_require__) {
        // ...
    })
});


二、多文件

为了 “抽取公共模块进行单独打包避免重复加载” 或 “增加并发请求数减少总加载时间” 等原因,一般会将代码拆分成多文件,可使用如下形式:

  • 使用 webpack 的 splitChunks 插件,将代码拆分成多个 chunk 文件;
  • 通过配置 external,将第三方库单独加载;

拆分成多个文件后,为了避免业务逻辑执行时相关文件还没加载完成导致执行出错,需要等待相关文件都加载完成后再开始执行。


2.1 等待 entry 与 chunk 文件都加载完成

entry 与 其他 chunk 文件的 “等待-执行” 的逻辑,webpack 其实已经帮我们自动生成了。


2.1.1 在生成的 entry 文件中

  • 声明了依赖的 chunk 文件列表
  • 当 chunk 文件加载后进行标记完成
  • 文件加载后将检查相关文件是否都加载完成,如是,则开始执行业务逻辑
  • 提供给 chunk 文件加载后的回调方法
// # entry.js

// 声明依赖列表
deferredModules.push(["./src/entryA.js","commons"]);

// 缓存已完成的加载
var installedChunks = {
    "entryA": 0
};

function webpackJsonpCallback(data) {
    // 加载后标记完成
    installedChunks[chunkId] = 0;
}

// 检查是否都加载完成,如是,则开始执行业务逻辑
function checkDeferredModules() {
    // 判断 installedChunks 是否完整
    // ...
    if(fulfilled) {
        // 所有都加载,开始执行
        result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
    }
}

// 提供给 chunk 的全局回调方法
var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
jsonpArray.push = webpackJsonpCallback;


2.1.2 在生成的 chunk 文件中

chunk 文件加载后,正常情况下将调用 entry 提供的全局回调方法,标记加载完成。而当 chunk 文件先于 entry 加载完成,则会先缓存记录,等 entry 文件加载后读取缓存并将其标记完成。

// # chunk.js

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["commons"],{
     "./src/moduleA.js":  (function(module, __webpack_exports__, __webpack_require__) {
           // ...
     })
}]);


2.1.3 小结

基于以上分析,可以看出 entry 和 chunk 文件加载顺序不会影响执行时机,只有在都加载完成后,才会执行业务逻辑。如下图示



2.2 等待 external 文件加载完成

项目引用第三方库,一般会配置 external 让库单独加载。通过 webpack 生成的代码可以看出,配置 external 的模块在业务代码执行前将被当作已存在环境中,不做任何判断。所以当 external 文件未加载完成或加载失败时,使用对应模块将会导致执行出错。

"react":  (function(module, exports) {
     eval("(function() { module.exports = window[\"React\"]; }());");
})


2.2.1 添加等待 external 文件加载完成再执行逻辑

为了避免使用时出错,在执行前需先保证 external 文件已经加载完成。处理方式如下

  • 将 entry 逻辑进行封装,不立即执行
  • external 模块不存在时,则监听等待文件加载完成后再判断执行
  • external 模块都存在后再执行 entry 逻辑

示意代码:

(function () {
    var entryInit = function () {
        (function(modules) {
            // webpackBootstrap
            //  ...
        })({})
    };
    if (window["React"]) {
        entryInit();
    } else {
        var hasInit = false; 
        var callback = function () {
            if(hasInit) return;
            if (window["React"]) {
                hasInit = true;
                document.removeEventListener('load', callback, true);
                entryInit();
            }
        };
        document.addEventListener('load', callback, true);
    }
})();


2.2.2 “自动”生成等待 external 文件加载完成再执行逻辑

等待 external 加载完成逻辑是统一的,差异在于依赖的 external 或有不同。为了避免手动添加出错,我们可以通过以 webpack 插件的形式自动分析依赖,并生成相关代码。

  • 获取依赖的 external Modules
  • 分析 external 对应变量
  • 生成并注入相关逻辑代码

具体实现可见插件 wait-external-webpack-plugin

通过 wait-external-webpack-plugin 插件,能够自动生成等待依赖的 external 文件加载完成再执行逻辑,对开发者透明,保证文件对正常执行。

原文地址

 

链接: https://fly63.com/article/detial/4448

js中for循环优化总结_如何提高程序的执行效率

在程序开发中,经常会使用到for循环的,但是很多人写的for循环效率都是比较低的,下面就举例说明,并总结优化for循环的方法,来提高我们程序的执行效率。

网站打开速度优化_如何提高网页访问速度技巧方法总结

网站的加载速度不仅影响着用户体验,也会影响搜索引擎的排名,在百度推出“闪电算法”以来,将网站首屏打开速度被列入优化排名行列,作为前端开发的我们需要如果来优化网站的打开速度呢?下面就整理挖掘出很多细节上可以提升性能的东西分享给大家

JS性能优化之文档片段createDocumentFragment

DocumentFragments是DOM节点。它们不是主DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。在DOM树中,文档片段被其所有的子元素所代替。因为文档片段存在于内存中,并不在DOM树中

深入浅出代码优化﹣if/else

对于代码裡面的 if else,我们可以使用逻辑判断式,或更好的三元判断式来优化代码。除了可以降低维护项目的成本之外,还可以提升代码可读性。就让我们从最简单的 if else 例子开始吧。

微信小程序性能优化入门指南

小程序从发布到现在也已经有将近两年的时间,越来越来多的公司开始重视小程序生态带来的流量,今年也由于小程序平台对外能力的越来越多的开放以及小程序平台的自身优化,越来越多的开发者也自主的投入到小程序的开发当中

网络串流播放_HTML5如何优化视频文件以便在网络上更快地串流播放

无论你正在将 GIF 动图转换为 MP4 视频,还是手头已经有一大堆 MP4 视频,你都可以优化文件结构,以使得这些视频更快地加载和播放。通过重组 atoms 将 moov 放到文件开头,浏览器可以避免发送额外的 HTTP range request 请求来搜寻和定位 moovatom

​web项目优化_Web 服务器性能与站点访问性能优化

要优化 Web 服务器的性能,我们先来看看 Web 服务器在 web 页面处理上的步骤:Web 浏览器向一个特定的服务器发出 Web 页面请求; Web 服务器接收到 web 页面请求后,寻找所请求的 web 页面,并将所请求的 Web 页面传送给 Web 浏览器; 显示出来

前端性能优化之重排和重绘

浏览器下载完页面所有的资源后,就要开始构建DOM树,于此同时还会构建渲染树(Render Tree)。(其实在构建渲染树之前,和DOM树同期会构建Style Tree。DOM树与Style Tree合并为渲染树)

微信小程序代码优化总汇

写篇文章的目的,是以开放小程序代码的层面的优化。包括:条件判断将wx:if换成了hidden 、页面跳转请销毁之前使用的资源、列表的局部更新、小程序中多张图片懒加载方案、Input状态下隐藏input,应预留出键盘收起的时间

我是如何将页面加载时间从6S降到2S的?

生活在信息爆炸的今天,我们每天不得不面对和过滤海量的信息--无疑是焦躁和浮动的,这就意味着用户对你站点投入的时间可能是及其吝啬的(当然有一些刚需站点除外)。如何给用户提供迅速的响应就显得十分重要了

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!