js 异步执行_webpack模块化原理-异步加载模块

2023-11-06

在上篇文章中,我们介绍了 webpack 同步加载模块的原理。这篇文章,我们来介绍一下 webpack 异步加载模块。

异步加载模块

还是先做一些准备工作。

首先定义一个依赖模块:math.js,math.js 采用 ES6 module 导出了两个函数 add 和 minus。

export function add(a, b) {
  return a + b;
}

export function minus(a, b) {
  return a - b;
}

然后定义一个入口模块:index.js,index.js 通过 import 函数导入了 math.js,然后调用了里面的 add 和 minus 方法。

import("./math").then(math => {
  console.log(math.add(2, 1));
  console.log(math.minus(2, 1));
});

最后再定义一个配置文件:webpack.config.js,内容和 webpack 同步加载模块中一样。

const path = require("path");

module.exports = {
  mode: "development",
  devtool: "source-map",
  entry: path.join(__dirname, 'index.js'),
  output: {
    filename: "main.js",
    path: path.join(__dirname, 'dist')
  }
};

在根目录下执行webpack --config webpack.config.js,就可以在 dist 目录下看到最终的生成产物了,可以看到 dist 目录下除了 main.js 外,还多了一个 0.main.js。我们通常把 main.js 称为同步 chunk,0.main.js 称为异步 chunk

先来看一下 main.js 文件中的代码。

main.js 代码片段

首先是 webpackBootstrap 的函数体,与同步加载模块相比,它新增了很多内容:

  • webpackJsonpCallback 函数:异步加载 chunk 后的 jsonp 回调函数
  • installedChunks 对象:缓存 chunk 加载状态,main 代表入口模块,0 表示模块已加载,因为入口模块是同步 chunk,所以默认就是已加载的
  • jsonpScriptSrc 函数:拼接 chunk 请求地址
  • __webpack__require__.e 函数:异步加载 chunk 函数
  • jsonp 初始化代码:初始化 jsonp 相关配置

接下来是 webapackBootstrap 的参数部分,与同步加载模块不同的是,它移除了依赖模块 main.js(main.js 中的内容都移入到了异步 chunk 文件 0.main.js 中)。

最后是入口模块 index.js,它使用 __webpack_require__.e 来异步下载依赖模块 math.js,在 math.js 下载完毕后,再使用 __webpack_require__ 来同步加载 math.js

看到这里,大家应该有个初步感觉了:webpack 异步加载模块,其实是通过 jsonp 的方式来实现的。

接下来看一下 __webpack_require__.e_ 的函数实现。

__webpack_requiore__.e 函数实现

__webpack_require__.e 中的代码比较多,先看一头一尾:最前面定义了一个 promise 数组 promises,最后面用 Promise.all 的方式返回了 promises。因此 __webpack_require__.e 中间的代码,其实都是用来操作 promises 数组的。具体是如何操作的,我们一步步来看。

首先是缓存查找,在 installedChunks 对象中根据 chunkId 来判断对应的 chunk 是否已加载,chunk 主要有三种状态,分别对应不同的处理:

  • 0:表示 chunk 已加载,这种情况下,不做处理,直接返回
  • 数组:表示 chunk 正在加载,这种情况下,会将缓存的 promise 对象压入 promises 数组中,等待 chunk 加载完毕
  • undefined:表示 chunk 第一次加载,这种情况下的操作包括:
    • 创建一个新的 promise 对象
    • 将新创建 promise 对象的 reject、resolve 方法以及 promise 对象本身都存放到 installedChunks 对象中
    • 将 promise 对象压入 promises 数组中

接下来是模块加载,模块加载使用 jsonp 的方式,首先会动态创建一个 script 标签,src 指向异步 chunk 地址,然后将 script 标签添加到 head 中,实现异步加载 chunk 的功能。

最后是异常处理,给 script 标签添加了 onloade 和 onerror 事件处理函数onScriptCompleteonScriptComplete 在判断模块加载超时或是加载失败的情况下(缓存的 chunk 不为 0),会调用之前保存的 reject 方法返回模块加载失败的异常,同时还会将 chunk 的缓存标识设置为 undefined,标识未加载。

从前面的流程中我们可以看到,__webpack_require__.e 主要是通过 jsonp 的方式来加载异步 chunk,同时通过 promise 对象来控制异步 chunk 的加载情况:在加载失败的情况下会调用 promise 对象的 reject 方法,在加载成功的情况会执行异步 chunk 文件,也就是 0.main.js。

再来看一下 0.main.js 中的代码。

0.main.js 代码片段

0.main.js 中的内容比较简单,主要是调用 window 上挂载的全局数组 webpackJsop 的 push 方法,push 的内容包括两部分:chunkId 数组和依赖模块函数,webpackJsonp 全局数组又是在哪里定义的呢?

jsonp 初始化代码

我们回到 webpackBootStrap 函数,可以看到,webpackJsonp 是在 jsonp 初始化代码中定义的,jsonp 初始化代码主要干了以下几件事:

  1. 定义了一个全局的 webpackJsonp 数组,用来存储所有的 jsonp 回调
  2. webpackJsonp 的原生 push 方法改写为了 webpackJsonpCallback
  3. webpackJsonp 原生的 push 方法保存为了 parentJsonpFunction

所以,在 0.main.js 中调用 webpackJsonp 的 push 方法,最终执行的是 webpackJsonpCallback 中的代码。

最后,看一下 webpackJsonpCallback 的函数实现。

webpackJsonpCallback 函数实现

首先是函数参数,data 参数分为两部分:

  • chunkIds:一个数组,包含当前 chunk 文件依赖的 chunkId,以及自身的 chunkId
  • moreModule:代表当前 chunk 带来的新模块,也就是咱们前面看到的模块执行函数

接下来是执行逻辑:

  1. 遍历 chunkIds 数组,判断 installedChunks 对象中的 chunk 是否处于加载中状态,如果返回数组,则表示正在加载中,在这种情况下,会取出缓存的 resolve 方法(installedChunks[chunkId][0]),放到 resolves 数组中,等下统一执行,同时,还会将对应的 chuk 设置为已加载
  2. moreModules 合并到 modules 对象中,便于后续同步加载
  3. 将 data 参数保存到 webpackJsonp 全局数组中
  4. 遍历 resolves 数组,执行前面缓存的 resolve 方法并清空数组,保证该模块加载开始前所有前置依赖内容包括它自身都已经被加载完毕

总结

总结一下,webpack 采用 jsonp 的方式来实现模块的异步加载:

    • 通过 __webpack_require__.e 实现动态加载
    • 通过 webpackJsonpCallback 实现异步回调

最后,我们用流程图来总结一下 webpack 异步加载模块的流程。

webpack 异步加载模块流程图
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

js 异步执行_webpack模块化原理-异步加载模块 的相关文章

  • 使用 VS2022 配置 QT 开发环境的步骤

    使用 VS2022 配置 QT 开发环境的步骤 QT 是一个跨平台的 C GUI 库 可以在 Windows Mac Linux 等操作系统上运行 在 Visual Studio 2022 中配置 QT 的开发环境 可以让开发者在 Wind
  • Label Assignment

    前言 今天在研究四点模型的时候 了解到一个新概念 Label Assignment 记录一下 Label assignment 参考文档 目标检测中的Label Assignment Label assignment 主要是指检测算法在训练
  • 文件翻转教学python

    目录 第1关 读文件全部内容到一个字符串 第2关 读文件前n个字符 第3关 逐行读取并输出文件内容 第4关 读取文件到列表中 第5关 读取文件中的数据到二维列表 第6关 将唐诗写入到文件中 第1关 读文件全部内容到一个字符串 任务描述 本关
  • OpenGL学习例程精析(3d纹理)

    OpenGL学习例程精析 3d纹理 代码分析 glPixelStorei 完整代码 最终效果 代码分析 3d纹理的配置要比2d纹理复杂一些 glPixelStorei glPixelStorei GL UNPACK ALIGNMENT 1
  • eclipse的安装和汉化

    eclipse是一个可扩展的开发平台 受到开发人员的欢迎与好评 其安装和汉化的步骤如下 在本文中涉及的网址都是官方网址 确保下载软件的安全 纯净 1 下载jdk1 8 0并安装 网址 http www oracle com technetw
  • 响应式数据大屏构造

    数据大屏构建 需求 UI 实现响应式数据大屏 适配各种屏幕 不允许出现滚动条 方案 rem 实现原理 根据屏幕宽度 计算1rem的宽度 配置根元素的font size 所有的像素单位按照rem计算 优点 实现响应式 根据设计稿和VW的宽度实
  • 海量图片曝光百度新家“搜索框”大厦

    今天陪朋友到百度办事 有幸参观了百度的新办公大楼 搜索框大厦 大厦特别漂亮 内部设计特别炫 功能更是酷啊 海量图片第一时间与大家分享一下 刚到上地环岛 远远就看到气势宏伟的大厦 非常醒目 波浪形的玻璃外墙 相当气派 无论从正面 侧面还是背面
  • fetch使用

    fetch基本使用方法 1 fetch与ajax作用相同 发送请求 2 ajax是使用XMLHttpRequest对象来请求数据 因此需要先new XMLHttpRequest 然后连接发送接收 3 fetch是一个方法 fetch 地址
  • vue中点击按钮关闭当前页面踩坑记录

    vue中关闭当前页面踩坑记录 当前页面直接使用window close不行 必须是新窗口才能使用window close 所以要router跳转时打开新窗口才能关闭 直接使用 不行 window close 先使用下面跳转对应页面 let
  • windows下两种方法通过cmd进入指定目录

    方法一 通过cmd cd命令进入 相同盘符下的目录可直接使用cd 但是windows下不同于linux 不能直接跨盘符cd进入目录 例如 从C盘进入E盘下面的目录 需要两行命令 跨盘符 跨盘符目录 先后顺序都可以 先输入跨盘符目录 再输入跨
  • C语言求班级平均分案例讲解

    我们先看例题 统计3个班成绩情况 每个班有5个同学 求出所有班级的平均分以及各个班级的平均分 从键盘输入成绩 思路分析 1 我们定义一个3行5列的二维数组用来存放学生的成绩 1行表示1个班的学生成绩 总共3行 可以存放3个班的成绩 每行有5
  • 菜鸟视角的openwrt(一) 初识openwrt

    作为一只菜鸟 为了熟悉openwrt系统 看了很多前辈的文章 因为写作的角度或者说目标人群不同 侧重点也不同 学到的知识零零碎碎 等积累的知识多了 回头再来看 才发现 原来如此 原来作者已经帮我们总结好了 这篇文章对老鸟来说 可以直接忽略
  • 二分模板——数的范围

    789 数的范围 先用二分求出x的左边界 a mid gt x mid在x的右边 所以右边界变为mid 即 if a mid gt x r mid else l mid 1 根据模板得出mid mid l r gt gt 1 若得出的左边界
  • stm32+DS1302+TM1638驱动程序

    TM1638数码管显示驱动程序 参考 1 TM1638与STM32连接 1 1 硬件连接 Vcc 电源 GND 电源地 STB PA0 CLK PA1 DIO PA2 1 2 驱动程序 TM1638 c文件 Program Assignme
  • MySQL基础入门语法

    一 数据库基础概念 1 1 数据库定义 数据库 存储数据的软件 长期存储在计算机内 有组织的数据集合 表 数据库存储数据的基本单位 数据按照分类存储到不同的表中 能够高效的的查询其中数据 对于测试工作 如果项目页面没有实现 需要校验数据 则
  • 数据结构之常见排序算法

    文章目录 1 排序概念 2 10种排序比较 3 排序算法 3 1直接插入排序 元素越有序 越高效 3 2希尔排序序 缩小增量排序 3 3直接选择排序 3 4堆排序 3 5冒泡排序 3 6快速排序 递归实现 无序使用最好 3 6 1挖坑法 建
  • 如何使用云桌面进行开发?

    云桌面又称桌面虚拟化 云电脑 是替代传统电脑的一种新模式 采用云桌面后 用户无需再购买电脑主机 主机所包含的CPU 内存 硬盘等组件全部在后端的服务器中虚拟出来 为什么要用云桌面进行开发 采用了云桌面 大量的终端电脑都可以统一集中管理 系统
  • vs2015写的程序,在vs2019下无法运行,报错代码为-1073741701

    vs2015写的程序 在vs2019下无法运行 报错代码为 1073741701 1 现象 2 vs2019下的配置 3 VS015下配置 4 在VS015下运行结果 5 解决 vs2019能够完美的向下兼容vs2017 vs2015的项目
  • C语言函数大全-- x 开头的函数(5)

    x 开头的函数 5 1 xdrmem create 1 1 函数说明 1 2 演示示例 2 xdrmem destroy 2 1 函数说明 2 2 演示示例 3 xdrrec create 3 1 函数说明 3 2 演示示例 4 xdrre

随机推荐

  • flutter手势onLongPress 的默认时间

    这个长按的时间是100ms左右 import dart async import package flutter material dart import package learn flutter02 extension size fit
  • DeviceDriver(十四):多点触摸(MT协议,Input子系统)

    Input子系统框架参考 02 输入子系统 猩猩 點燈的博客 CSDN博客 电阻式多点触摸驱动参考 05 触摸屏驱动 猩猩 點燈的博客 CSDN博客 一 电容触摸屏知识点 1 电容触摸屏是I2C接口 需要触摸IC 因此框架为I2C设备驱动框
  • 文件上传upload-labs第十一至十九关

    第十一关 白名单 get类型 00截断 需要两个条件 php版本小于5 3 4 php的magic quotes gpc为OFF状态 另save path等于下面的值 upload 4 php 00 BP修改一下抓到的包 第十二关 POST
  • 【MySQL存储过程】存储过程的查看与删除

    目录 一 查看存储过程 1 SHOW STATUS语句查看存储过程 2 使用SHOW CREATE语句查看存储过程的定义 3 从information schema Routine表中查看存储过程的信息 二 存储过程的删除 一 查看存储过程
  • QT中HASH函数方法

    包含的头文件 include QCryptographicHash 具体代码实现 通过hash中的sha1加密方式加密 QCryptographicHash Hash QCryptographicHash Sha1 QString word
  • pdf文件太大如何处理?教你pdf压缩简单方法

    PDF文件过大 是很多人在使用PDF文件时都遇到过的一个常见问题 过大的PDF文件不仅会占用大量的存储空间 还会影响文件传输和处理效率 下面给大家总结了几个方法 帮助大家解决PDF文件过大的问题 方法一 嗨格式压缩大师 这是一款专业的文件压
  • PSM:协议状态机(Protocol State Machine),一款用于流式传输的数据协议解析组件

    PSM 协议状态机 Protocol State Machine 一款用于流式传输的数据协议解析组件 介绍 PSM Protocol State Machine 协议状态机 一款用于流式传输的数据协议解析组件 可有效解决沾包 断帧问题 PS
  • 文字识别:Tesseract OCR

    一 安装并配置Tesseract 1 下载Tesseract OCR 网上直接下载即可 2 双击安装 选择所有人均可使用 避免权限问题 勾选最后一项添加语言包 但是全部勾选需要1 3G 可以点开加号 选择自己所需的语言包即可 注意 这里最好
  • 面试经典(4)--链表逆序

    题目 输入单链表的头结点 反转链表并输出反转之后的头结点 pNode代表当前节点 修改pNode的时候 要知道他的前面节点 并保存后面节点 因为一旦pNode gt next被修改 就和后边断开 ListNode reverse ListN
  • MySQL报错:this is incompatible with sql_mode=only_full_group_by

    错误场景 今天在自己电脑运行一个刚clone下来的项目 在登录完成进入主页的时候 报了一串this is incompatible with sql mode only full group by 错误 我很确定之前在公司电脑上是不会有这个
  • 如何命令杀死yarn的作业

    yarn application kill 命令即可kill掉
  • php安装swoole扩展(linux)

    在Linux中php安装swoole扩展 相关环境 LAMP或LNMP开发环境 L 指linux A 指Apache M 指MySQL P 指PHP N 指Nginx 下载swoole wget c https github com swo
  • 33 KVM管理设备-配置虚拟机PCIe控制器

    文章目录 33 KVM管理设备 配置虚拟机PCIe控制器 33 1 概述 33 2 配置PCIe Root PCIe Root Port和PCIe PCI Bridge 33 2 1 简化配置方法 33 2 1完整配制方法 33 KVM管理
  • 提供许可证到期新通知!标签管理软件BarTender v2019 R5上线!

    BarTender在150多个国家 地区拥有成千上百的用户 在标签 条形码 证卡和 RFID 标记的设计和打印领域是全球首屈一指的软件 BarTender既可以单独运行 也可以与任何其他程序集成 几乎是所有按需打印或打标应用的完美解决方案
  • 【网络编程】---C++实现原始套接字捕获数据包

    C 实现原始套接字捕获数据包 引言 原始套接字与TCP套接字和UDP套接字的区别 原始套接字编程使用的场合 原始套接字的通信过程 1 基于原始套接字的数据发送过程 2 基于原始套接字的数据接收过程 创建原始套接字 常用协议定义列表 使用原始
  • 显著性检测的四种经典方法

    最近闲来蛋痛 看了一些显著性检测的文章 只是简单的看看 并没有深入的研究 以下将研究的一些收获和经验共享 先从最简单的最容易实现的算法说起吧 1 LC算法 参考论文 Visual Attention Detection in Video S
  • angualr学习笔记3-angular模型(model)

    AngularJS ng model 指令 ng model 指令用于绑定应用程序数据到 HTML 控制器 input select textarea 的值 ng model 指令 ng model 指令可以将输入域的值与 AngularJ
  • 执行yum软件包索引步骤报错

    解决 进入目录 cd etc yum repos d 执行rm rf删除所有 rm rf 然后 yum update 重新设置yum源 curl o etc yum repos d CentOS Base repo http mirrors
  • 生活总是不经意给你开个玩笑_你在开玩笑的故事吗

    生活总是不经意给你开个玩笑 In 1994 Vincent Connare who had previously designed type at Apple and Agfa Compugraphic was working at Mic
  • js 异步执行_webpack模块化原理-异步加载模块

    在上篇文章中 我们介绍了 webpack 同步加载模块的原理 这篇文章 我们来介绍一下 webpack 异步加载模块 异步加载模块 还是先做一些准备工作 首先定义一个依赖模块 math js math js 采用 ES6 module 导出