聊一聊 webpack 中的 preloading 和 Prefetching
聊一聊 webpack 中的 preloading 和 Prefetching
提到 Preloading 和 Prefetching 就不得不先说一下代码分割,通过下面的例子我们来说明为什么需要代码分割?
// index.js
import _ from 'lodash'; // 假设大小为 1 MB
业务代码 // 假设大小为 1 MB
- 在首次访问时, index.js 文件的大小为 2 MB,需要加载的大小是 2 MB
- 业务代码改变用户再次访问时,index.js 的大小为 2 MB,需要加载的大小还是 2 MB
现在进行代码分割:
// src/index.js
业务代码 // 假设大小为 1 MB
// src/lodash.js
import _ from 'lodash';
window._ = _; // 以后在其它文件中使用 _ 就可以使用 lodash 库了。
首次访问时,index.js 1 MB,lodash.js 1 MB , 需要加载的大小是 2 MB,而且此时可以进行并行加载,速度一般会比上面的快。
业务代码改变用户再次访问时,index.js 1 MB,由于 lodash.js 文件并没有发生变化,所以无需再次加载,因为浏览器的缓存中有,所以此次只需加载 1 MB。
从上面的例子可以看出,代码分割提高了性能,但是第一次访问的时间并没有减少多少,webpack 想让第一次访问的时候也得到很大的优化。
我们先从 webpack 中的 SplitChunkPlugin 的默认配置中找到答案,
optimazition: {
splitChunks: {
chunks: 'async', // 异步代码才会进行代码分割
...
}
}
我们可以看到,chunks 的配置是 async ,只有当异步时才会进行代码分割。
webpack 为什么要这样默认设置呢?
还是从下面的例子来说明:
创建一个div元素,并在页面上显示出来。
// index.js
document.addEventListener('click', () => {
const div = document.createElement('div');
div.innerHTML = 'hello webpack';
document.body.appendChild(div);
});
思考上面的代码写的有问题吗?还有优化的空间吗?
现在我们将上面的代码打包在浏览器中运行,在浏览器中 按 Ctrl + Shift + P ,然后在弹出的对话框中输入 coverage ,点击回车,然后再点击下面的小黑原点,小黑圆点变成红圆点之后,刷新页面,会出现下图所示的页面:

从红色的方框中可以看出当前加载的文件中在当前页面中的利用率为 74.6% 。
仔细分析一下上面的代码,在回调函数中的下面三行代码只有在点击页面之后才会有用,因此加载页面时没必要加载它们。
const div = document.createElement('div');
div.innerHTML = 'hello webpack';
document.body.appendChild(div);
现在我们换一种写法,将它们异步加载进来,现在新建一个 click 文件:
// click.js
function handleClick() {
const div = document.createElement('div');
div.innerHTML = 'hello webpack';
document.body.appendChild(div);
}
export default handleClick;
然后改写 index.js 文件:
document.addEventListener('click', () => {
import('./click.js').then(({default: func}) => {
func();
})
});
这时候将异步代码写在一个单独的文件中,只有当点击页面时才会去加载 click.js 这个文件。
现在再看此时的代码利用率为 75% 有了一点提升,设想如果异步加载在的代码比较大的话,提升的会比较多。

现在我们就看出来 webopack 为什么要使用 chunks: 'async' 这样的默认配置了。
webpack 优化的侧重点是代码的使用率而不是缓存,只是使用缓存的方式来优化意义是不大的,通过异步的方式提高代码的利用率才能比较大程度地提高网站的性能。
这也是为什么老提倡写异步代码的原因。
现在又有一个问题,只有当用户点击页面时才会加载 click.js这个文件,那么如果这个文件很大,那加载的时间也会很长呀,用户体验也不高呀。
那这个问题应该如何解决呢?
有些小伙伴可能会想,能不能在加载完页面网络空闲的时候先把这些文件加载进来呀,真聪明,这就是接下来要讲的 Preloading 和 Prefetching。
Prefetching
使用方法也比较简单,就是在要异步加载的文件前面加上
/* webpackPrefetch: true */这个 magic comment 即可。document.addEventListener('click', () => {
import(/* webpackPrefetch: true */ './click.js').then(({default: func}) => {
func();
})
});

上图中的 0.js 是 click.js 打包之后,可以看出在页面加载完之后的空闲时间还没有点击页面时已经加载了 0.js ,当点击页面时,0.js 直接从缓存中读取,因此耗时非常短。
Preloading 和 Prefetching 有什么区别?
两者的最大区别在于,Prefetching 是在核心代码加载完成之后带宽空闲的时候再去加载,而 Preloading 是和核心代码文件一起去加载的。
因此,使用 Prefetching 的方式去加载异步文件更合适一些,不过要注意浏览器的兼容性问题。
完, 如有不恰当之处,欢迎指正哦。
聊一聊 webpack 中的 preloading 和 Prefetching的更多相关文章
- Webpack中hash与chunkhash的区别,以及js与css的hash指纹解耦方案
文件的hash指纹通常作为前端静态资源实现增量更新的方案之一,Webpack是目前最流行的开源编译工具之一,其强大的功能也带来很多坑(当然,大部分麻烦其实都可以在官方文档中找到答案). 比如,在Web ...
- webpack中利用require.ensure()实现按需加载
webpack中的require.ensure()可以实现按需加载资源包括js,css等,它会给里面require的文件单独打包,不和主文件打包在一起,webpack会自动配置名字,如0.js,1.j ...
- webpack中实现按需加载
webpack中的require.ensure()可以实现按需加载资源包括js,css等,它会给里面require的文件单独打包,不和主文件打包在一起,webpack会自动配置名字,如0.js,1.j ...
- [转] webpack中配置Babel
一.安装 npm install --save-dev babel-loader babel-core babel-preset-env 二.在webpack.config.js中配置module 1 ...
- [转]webpack中require和import的区别
webpack中可以写commonjs格式的require同步语法,可以写AMD格式的require回调语法,还有一个require.ensure,以及webpack自己定义的require.incl ...
- webpack中插件 prerender-spa-plugin 来进行SEO优化(二十四)
vue.react对于开发单页应用来说带来了很好的用户的体验,但是同样有缺点,比如首页加载慢,白屏或SEO等问题的产生.为什么会出现这种情况呢?我们之前开发单页应用是这样开发的,比如首页 index. ...
- 如何在webpack中成功引用到图片?
打包图片时,你可曾遇到在产出目录文件夹找不到图片,即便找到了,但是页面说引用不到资源?页面上或者文件中引用的图片地址不对? 一.在webpack中引入图片需要url-loader //webpack配 ...
- webpack中如何使用vue
1.安装 vue包:npm i vue -S 2.由于在webpack中,推荐使用.vue这个组件模版文件来定义组件,不然会出现vue.js移动和一些高级语法的不支持,因此需要安装能解析这种文件的lo ...
- Webpack中publicPath设置
webpack中的path是当我们build的时候,输出项目打包文件的位置. webpack中的publicPath是我们打算放到web服务器下的目录,如果我们要放到网站的根目录下,那么就无需设置.如 ...
随机推荐
- MySQL通过自定义函数实现递归查询父级ID或者子级ID
背 景: 在MySQL中如果是有限的层次,比如我们事先如果可以确定这个树的最大深度, 那么所有节点为根的树的深度均不会超过树的最大深度,则我们可以直接通过left join来实现. 但很多时候我们是无 ...
- Acid burn crackme 的第一道分析
1.首先查下壳: 没壳,一个用delphi写的程序. 接下来就直接丢OD看看了,看一下界面, 就是这里需要验证了,然后下个bp MessageBoxA 断点 就直接跳到这来了: 在栈中返回到上一级去, ...
- 菜鸟系列Fabric源码学习—orderer服务启动
Fabric 1.4 orderer 服务启动流程 1.提要 orderer提供broadcast和deliver两个服务接口.orderer节点与各个peer节点通过grpc连接,orderer将所 ...
- python 实现图片批量加入水印!pillow 入门实战!
写文章的时候可以设置是否添加水印.可是,有些图片可能想加水印,有些不想加水印,该怎么办呢? 配置环境 python3 + pillow pip3 install pillow 引入库 from PIL ...
- springboot+swagger接口文档企业实践(下)
目录 1.引言 2. swagger接口过滤 2.1 按包过滤(package) 2.2 按类注解过滤 2.3 按方法注解过滤 2.4 按分组过滤 2.4.1 定义注解ApiVersion 2.4.2 ...
- linux终端操作
------------恢复内容开始------------ tab键自动补全 ls列出当前文件目录: 默认是当前目录 “.”代表当前目录 “..”代表父目录 -a显示所有,而隐藏文件的第一字符为点“ ...
- 实现自定义的参数解析器——HandlerMethodArgumentResolver
1.为什么需要自己实现参数解析器 我们都知道在有注解的接口方法中加上@RequestBody等注解,springMVC会自动的将消息体等地方的里面参数解析映射到请求的方法参数中. 如果我们想要的信息不 ...
- 使用selenium模拟登陆新浪微博
1.selenium基本使用 1.selenium安装及基本操作 selenium是一个自动化测试工具,它支持各种浏览器,包括Chrome,Safari,Firefox等主流界面浏览器驱动,也包括Ph ...
- AI手写输入法 - pytorch从入门到入道(二)
本章承接上一篇的手写数字识别,利用训练好的模型,结合pyqt画板,实现简易手写输入法,为"hello world"例子增添乐趣. pyqt是开发图形界面的框架,可以百度查找相关资料 ...
- 【Android - 进阶】之Dialog分类及使用
1.确定取消对话框 代码: // 使用AlertDialog.Builder初始化对话框 AlertDialog.Builder builder0 = new AlertDialog.Builder( ...