提到 Preloading 和 Prefetching 就不得不先说一下代码分割,经过下面的例子咱们来讲明为何须要代码分割?webpack
// index.js import _ from 'lodash'; // 假设大小为 1 MB 业务代码 // 假设大小为 1 MB
如今进行代码分割:web
// 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 的默认配置中找到答案,app
optimazition: { splitChunks: { chunks: 'async', // 异步代码才会进行代码分割 ... } }
咱们能够看到,chunks
的配置是 async
,只有当异步时才会进行代码分割。异步
webpack 为何要这样默认设置呢?async
仍是从下面的例子来讲明:函数
建立一个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 的方式去加载异步文件更合适一些,不过要注意浏览器的兼容性问题。
完, 若有不恰当之处,欢迎指正哦。