webpack异步加载的原理

webpack ensure相信大家都听过。有人称它为异步加载,也有人说做代码切割,那这 个家伙到底是用来干嘛的?其实说白了,它就是把js模块给独立导出一个.js文件的,然后使用这个 模块的时候,webpack会构造script dom元素,由浏览器发起异步请求这个js文件。

场景分析:

比如应用的首页里面有个按钮,点击后可以打开某个地图。打开地图的话就要利用百度地图的js,于是 我们不得不在首页中把百度地图的js一起打包进去首页,一个百度地图的js文件是非常大的,假设为 1m,于是就造成了我们首页打包的js非常大,用户打开首页的时间就比较长了。

有没有什么好的解决方法呢?

解决1

既然打包成同一个js非常大的话,那么我们完全可以把百度地图js分类出去,利用浏览器的并发请求 js文件处理,这样的话,会比加载一个js文件时间小得多。嗯,这也是个不错的方案。为baidumap.js 配置一个新的入口就行了,这样就能打包成两个js文件,都插入html即可(如果baidumap.js被多个 入口文件引用的话,也可以不用将其设置为入口文件,而且直接利用CommonsChunkPlugin,导出到一个 公共模块即可)可以参考我之前文章 webpack模块打包

那还有没有更好的解决方案呢?

解决2

当然还是有的!我们细想,百度地图是用户点击了才弹出来的,也就是说,这个功能是可选的。那么解决 方案就来了,能不能在用户点击的时候,我在去下载百度地图的js.当然可以。那如何实现用户点击的时候 再去下载百度地图的js呢?于是,我们可以写一个按钮的监听器

mapBtn.click(function() {
//获取 文档head对象
var head = document.getElementsByTagName('head')[0];
//构建 <script>
var script = document.createElement('script');
//设置src属性
script.async = true;
script.src = "http://map.baidu.com/.js"
//加入到head对象中
head.appendChild(script);
})

上面的几行代码对大家来说都不难。可以在点击的时候,才加载百度地图,等百度地图加载完成后,在 利用百度地图的对象去执行我们的操作。ok,讲到这里webpack.ensure的原理也就讲了一大半了。 它就是 把一些js模块给独立出一个个js文件,然后需要用到的时候,在创建一个script对象,加入 到document.head对象中即可,浏览器会自动帮我们发起请求,去请求这个js文件,在写个回调,去 定义得到这个js文件后,需要做什么业务逻辑操作。

ok,那么我们就利用webpack的api去帮我们完成这样一件事情。点击后才进行异步加载百度地图js,上面 的click加载js时我们自己写的,webpack可以轻松帮我们搞定这样的事情,而不用我们手写

mapBtn.click(function() {
require.ensure([], function() {
var baidumap = require('./baidumap.js') //baidumap.js放在我们当前目录下
})
})

搞定!当然还是分析一下。require.ensure这个函数是一个代码分离的分割线,表示 回调里面的require 是我们想要进行分割出去的,即require(’./baidumap.js’),把baidumap.js分割出去,形成一个 webpack打包的单独js文件。当然ensure里面也是可以写一些同步的require的,比如


var sync = require('syncdemo.js') //下面ensure里面也用到 mapBtn.click(function() {
require.ensure([], function() {
var baidumap = require('./baidumap.js') //baidumap.js放在我们当前目录下
var sync = require('syncdemo.js') //这个不会独立出去,因为它已经加载到模块缓存中了
})
})

也就是说,ensure会把没有使用过的require资源进行独立分成成一个js文件. require.ensure的 第一个参数是什么意思呢?[], 其实就是 当前这个 require.ensure所依赖的其他 异步加载的模块。你想啊?如果A 和 B都是异步加载的,B中需要A,那么B下载之前,是不是先要下载A啊?,所以ensure的第一个参数[] 是它依赖的异步模块,但是这里需要注意的是,webpack会把参数里面的依赖异步模块和当前的需要分离出去的异步模块给一起打包成同一个js文件,这里可能会出现一个重复打包的问题, 假设A 和 B都是异步的, ensure A 中依赖B,ensure B中 依赖A,那么会生成两个文件,都包含A和B模块。 如果想加载A require.ensure([‘A.js’],function) 即可

说完了上面的原理。下面就实践一下

entry.js 依赖三个 js。

  • Abtn-work.js 是封装了 abtn按钮点击后,才执行的业务逻辑
  • Bbtn-work.js 是封装了 bbtn按钮点击后,才执行的业务逻辑
  • util.js 是封装了 entry.js需要利用的工具箱

针对上面的需求,优化方案

假设 Abtn-work.js Bbtn-work.js util.js都是非常大的文件 因为 Abtn-work.js Bbtn-work.js 都不是entry.js必须有的,即可能发生的操作,那么我们把 他们利用异步加载,当发生的时候再去加载就行了

util.js是entry.js立即马上依赖的工具箱。但是它又非常的大,所以将其配置打包成一个公共模块, 利用浏览器的并发加载,加快下载速度。ok,构思完成,开始实现

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>index</title>
</head>
<body>
<div id="aBtn">Abtn</div>
<div id="bBtn">Bbtn</div>
</body>
</html>

定义了两个buttom

然后看看 entry.js


var util_sync = require('./util-sync.js') alert(util_sync.data) document.getElementById("aBtn").onclick = function() { require.ensure([], function() {
var awork = require('./workA-async.js')
alert(awork.data)
//异步里面再导入同步模块--实际是使用同步中的模块
var util1 = require('./util-sync.js')
})
} document.getElementById("bBtn").onclick = function() { require.ensure([], function() {
var bwork = require('./workB-async.js')
alert(bwork.data)
})
}

可以看到,workA-async.js, workB-async.js 都是点击后才ensure进来的。什么时候加载完成呢? 就是 require.ensure() 第二个函数参数,即回调函数,它表示当下载js完成后,发生的因为逻辑

webpack打包后,形成

其实, 1.1… 2.2…就是我们ensure导出来的js文件

我们看看代码是如何加载的执行的,点击打包插入js后的html

可以看到,并没有加载 ensure导出来的 1.1…js 2.2…js

点击 abtn,

发现浏览器下载并加载了 1.1…js

点击 bbtn

发现浏览器下载并加载了 2.2…js

ok 全部完成

webpack代码分离 ensure 看了还不懂,你打我(转)的更多相关文章

  1. Webpack 代码分离

    Webpack 代码分离 代码分离是 webpack 中最引人注目的特性之一. 你可以把你的代码分离到不同的 bundle 中,然后你就可以去按需加载这些文件. 总的来说, webpack 分离可以分 ...

  2. 详细!Mybatis-plus常用API全套教程,我就不信你看完还不懂!

    前言 官网:Mybatis-plus官方文档 简化 MyBatis ! 创建数据库 数据库名为mybatis_plus 创建表 创建user表 DROP TABLE IF EXISTS user; C ...

  3. 深度分析:面试阿里,字节跳动,美团90%被问到的List集合,看完还不懂算我输

    1 List集合 1.1 List概述 在Collection中,List集合是有序的,可对其中每个元素的插入位置进行精确地控制,可以通过索引来访问元素,遍历元素. 在List集合中,我们常用到Arr ...

  4. webpack代码分离CommonsChunkPlugin插件的使用(防止重复)

    1.webpack.config.js中添加: const path = require('path'); + const webpack = require('webpack'); const HT ...

  5. Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!

    本文原题“从实践角度重新理解BIO和NIO”,原文由Object分享,为了更好的内容表现力,收录时有改动. 1.引言 这段时间自己在看一些Java中BIO和NIO之类的东西,也看了很多博客,发现各种关 ...

  6. webpack学习之—— Code Spliting(代码分离)

    代码分离特性能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件.代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间. 有三种常 ...

  7. 看完此文还不懂NB-IoT,你就过来掐死我吧...【转】

    转自:https://www.cnblogs.com/pangguoming/p/9755916.html 看完此文还不懂NB-IoT,你就过来掐死我吧....... 1 1G-2G-3G-4G-5G ...

  8. 看完此文还不懂NB-IoT,你就过来掐死我吧...

    看完此文还不懂NB-IoT,你就过来掐死我吧....... 1 1G-2G-3G-4G-5G 不解释,看图,看看NB-IoT在哪里? 2 NB-IoT标准化历程 3GPP NB-IoT的标准化始于20 ...

  9. 使用Webpack的代码分离实现Vue懒加载(译文)

    当一个Vue的项目体积变得十分庞大的时候,使用Webpack的代码分离功能将Vue Components,routes或Vuex的代码进行分离并按需加载,会极大的提高App的首屏加载速度. 在Vue的 ...

随机推荐

  1. CentOS修改Tomcat端口号

    Linux下修改Tomcat默认端口 1.方法一 假设tomcat所在目录为/usr/local/apache-tomcat/ 1.打开tomcat配置文件 # vi /usr/local/apach ...

  2. 监控 Linux 性能的 18 个命令行工具[转]

    对于系统和网络管理员来说每天监控和调试Linux系统的性能问题是一项繁重的工作.在IT领域作为一名Linux系统的管理员工作5年后,我逐渐认识到监控和保持系统启动并运行是多么的不容易.基于此原因,我们 ...

  3. 日常API之图灵聊天机器人

    机器人是什么?可以吃吗? 嗯,他可以和你聊天,不能吃哦. 首先需要到www.tuling123.com注册一只KEY,你才能调用机器人API哦 一.布局 (控制台程序可以跳过这一步)本文以WPF为示例 ...

  4. Apache Traffic Server服务搭建

    一.简介 Apache Traffic Server(ATS或TS)是一个高性能的.模块化的HTTP代理和缓存服务器,与 Nginx 和 Squid 类似.它通过将频繁访问的信息缓存在网络的边缘来改善 ...

  5. 图说:为什么Java中的字符串被定义为不可变的

    8张图,看懂Java字符串的不变性 字符串,想必大家最熟悉不过了,通常我们在代码中有几种方式可以创建字符串,比如:String s = "Hollis";这时,其实会在堆内存中创建 ...

  6. loadrunner调用jar包方法

    环境 win7(32位)/winXP+loadrunner11+JDK 1.6(一定要配置JAVA环境变量) 1.Eclipse中创建com.medivh包 package com.medivh; p ...

  7. 51NOD 1220 约数之和 [杜教筛]

    1220 约数之和 题意:求\(\sum_{i=1}^n \sum_{j=1}^n \sigma_1(ij)​\) \[ \sigma_0(ij) = \sum_{x\mid i}\sum_{y\mi ...

  8. BZOJ 1176: [Balkan2007]Mokia [CDQ分治]

    题意: 有一个n * n的棋盘,每个格子内有一个数,初始的时候全部为0.现在要求维护两种操作: 1)Add:将格子(x, y)内的数加上A. 2)Query:询问矩阵(x0, y0, x1, y1)内 ...

  9. 关于WebApi 跨域问题的解决的方式

    最近在做WebApi 进行开发的时候 一直会遇到跨域方面的问题那么如何进行跨域问题其实非常的简单. 1.一直在使用WebApi的时候总是遇到跨域的问题 那么 什么是跨域?跨域,指的是浏览器不能执行其他 ...

  10. 如何使用JS实现banner图滚动

    通过JS实现banner图的滚动主要是定时器的应用 先新建好banner图的几张图片,最后一张与第一张用同一个,保证滚动的不间断 改好样式,需注意所有图片要在同行显示,否则不能向左滚动 声明一个函数, ...