likes
comments
collection
share

首屏加载时间优化之在工作中实践

作者站长头像
站长
· 阅读数 15

一、背景

作为一个唯唯诺诺的大三前端人终于出去实习了,在公司的第一个需求是针对公司的某个B端后台系统进行初次加载白屏时间优化的,那为什么要进行优化呢?

1、白屏时间长影响体验效果

这个后台在第一次加载(也就是还没有缓存)的时候的白屏时间是比较长,网络好的时候会像图片这样转个三秒多,网络不好的时候四五秒,甚至六七秒也是常有的事。这么长的时间是会影响用户体验的呀!要是客户因为这个不买我们的产品怎么办!于是领导就给我提了几个优化的方式,我就从性能优化和webpack的新手走上了这条优化之路。

首屏加载时间优化之在工作中实践


2、另一个新做的后台系统加载速度快说明有优化的空间

为什么会觉得这个后台系统有优化的空间呢?因为其实公司最近开发的另一个后台系统的加载速度是很快的,一两秒就能加载出来。这说明是有优化的可能性的,也许是他们在webpack打包配置上有一些差别导致了他们速度的不同。那么接下来我们就来思考一下有什么不同吧!

二、思考

1、旧后台与新后台的区别

通过研究发现,旧后台和新后台的主要区别在于:

首屏加载时间优化之在工作中实践

针对第一点 :也许是因为vue-cli5升级了一些配置方面的内容,才导致新后台比较快?接下来我们应该重点看看两个版本的vue-cli脚手架有什么不同点。

针对第二点:通过了解发现,多模板方案在当时上线的时候是比较仓促的,也许会有一些优化的地方,接下来我们也应该重新阅读多模板的代码和请求来试图优化它。

(注:多模板方案是指:针对不同的SaaS后台,会通过判断是何种后台来向服务器请求对应的资源来进行加载,其实也就是我们所常说的微前端

2、旧后台与新后台加载流程对比

首屏加载时间优化之在工作中实践 上图是浏览器从开始发起请求到显示出内容所进行的请求流程。

我们发现旧后台比新后台是多了两个请求的部分的,一是多模板资源的请求,二是莫名地多请求了200多个细碎的chunk文件。

而一个页面的最终呈现,是一定要把当前页面所需的内容请求完才会呈现,包括当前页面所需要的js和css资源,以及当前页面所需要展示的数据。

通过研究发现,这200多个细碎的chunk资源根本不是当前页面的内容,而是其他页面的内容,它们是通过    <link rel="prefetch"> 的方式引入到页面的,是prefetch的资源,而他们却在当前页面所需的内容前请求了,200多个请求那得占用多少时间呀?怪不得旧后台加载速度这么慢了!!!

3、白屏时间长的因素

针对以上,我们总结一下发现的问题及其思考的解决方法:

细碎chunk文件的问题:

①阻碍当前页面资源加载

是否是我们第一点中提到的vue-cli4与vue-cli5配置不同导致打包出来的文件有差异呢?那能不能从配置入手解决?

或者通过手动延时的方式让他们晚点再引入进来,这样就不会阻碍啦?

②200多个才几KB的文件都要单独请求,导致了很多tcp连接和等待http请求的时间

(一般来说像chrome机制只能同时进行6个以内的tcp连接)

多模板引入比较仓促导致的问题:

①loadAssets.js文件没有压缩,并且要单独请求(文件很小,不太划算)

注:loadAssets.js文件就是多模板方案向服务器请求当前后台所需资源的脚本文件

②webpack-assets.json作为一个静态文件却进行了options请求

注:webpack-assets.json文件是存储当前后台所需资源的文件名们的文件

原因是因为在代码逻辑上出现了问题,只要获取了token,不管啥请求在请求时都往它的请求头上加token,所以才导致不需要options请求的静态文件有了options请求,如下图:

三、方案

针对以上问题,我们一一来解决,

1、针对加载细碎chunk(prefetch)资源阻碍当前资源加载的问题

要解决这个问题,首先得搞清楚它出现的原因。刚刚我们讲了这么久这个资源是prefetch资源,其实还没有深入了解它到底是个什么吧,我们先来说一下prefetch到底是个啥吧

①prefetch资源是什么?为啥要阻碍当前页面所需要的资源?

网上的解释:prefetch资源是一种浏览器机制,其利用浏览器空闲时间 来加载(但不执行)用户在不就的将来可能会访问 的资源毛并缓存在内存中。在实际使用时可以节省加载资源的时间。

大家看到“空闲时间”两个字,可能会和我一个想法,当前资源都没加载完,这算哪门子空闲啊?

原来浏览器所认为的空闲时间,其实是它所定义的“高优先级任务”的加载间隔时间,而浏览器的加载机制就是:在空闲时间加载低优先级任务,prefetch资源的加载就属于低优先级任务。而当前所需资源的加载就包含在高优先级任务里面。就出现了下图这样乌龙的情况:浏览器在两个部分的高优先级资源之间加载了低优先级资源(prefetch资源)。

首屏加载时间优化之在工作中实践

这样就搞清楚这个问题的原因了。

②为什么会出现prefetch资源?

其实搜索发现,当前vue-cli5搭建的新后台是已经禁掉了prefetch资源,所以也搞清楚了为啥这200多个细碎的chunk文件活动后台没有,而新版直播后台有。 在vue-cli4中:默认配置了PreloadPlugin来把懒加载的资源(未来可能会访问的)link进html中,并配置属性rel为prefetch

首屏加载时间优化之在工作中实践

(在终端输入:npx vue-cli-service inspect > output.js来生成一个文件来查看vue.config.js全部的配置项)

首屏加载时间优化之在工作中实践

基于以上,提出两套解决方案:

· 通过配置直接干掉prefetch

· 在脚本中写定时器手动延迟prefetch资源的加载

其中我们优选选择第二个,因为前面也提到了prefetch资源可以在浏览器闲时加载,这样会让我们在多个页面中节省时间。

方案一:直接在webpack打包时处理成不生成prefetch资源

  • 在vue-config.js中配置

首屏加载时间优化之在工作中实践

此外,在多模板的情况下还需要做额外处理: 因为多模板的流程是:应用入口页(loadAssets.js)去请求记录资源的json文件,再逐一把资源link到html中,所以它也会对link做处理。我们需要在代码中把link prefetch资源的部分注释掉,如图:首屏加载时间优化之在工作中实践

方案二:延迟加载prefetch资源加载到当前页面资源请求后

· 通过轮询判断当前页面的DOM元素是否加载,如果加载完了就再加载prefetch资源

· 选择的这个DOM元素必须后台所有页面都共有,因为可能会从不同的导航页面进入

首屏加载时间优化之在工作中实践

2、针对细碎js/css导致太多http请求的问题

虽然通过上述方法,我们已经解决了把这些prefetch资源延后加载了,已经不会影响当前页面加载,但细碎js/css导致的太多http请求的问题我们还是做一下处理比较好。

在前面我们也分析过了,这些细碎js和css的出现是因为vue-cli4的配置默认会把每个页面懒加载的资源打成单独的一个chunk文件。那我们能不能也通过配置把这些细碎文件合并起来呢? ——通过插件在打包时吧这些细碎js和css合并

首屏加载时间优化之在工作中实践

(通过MinChunkSizePlugin这个webpack的内置插件,它可以通过合并小于minChunkSize的块来保持chunk的最小大小,单位是字节。)

3、针对多模板的loadAsset.js没有压缩并且要单独请求的问题

如字面意思想要解决就压缩并内联到html中就好了

方式一:手动命令压缩+手动内联

npx terser ./src/index.js -o ./terser/defult.js

这种方式虽然操作起来最快,也不需要思考,但如果每一次修改这个文件都要操作一遍就有点麻烦了,所以提出了第二个方法

方式二:自定义plugins插件每次打包的时候自动操作

压缩: 压缩工具有:terser和uglifyjs

他们的主要区别是terser支持es6+语法,而uglifyjs不支持,但我们现在的loadAssets.js脚本都是es5写的,所以用这两个都可以,处理写法也差不多。

首屏加载时间优化之在工作中实践

内联:

写一段原生脚本,在获取到html的内容后进行处理,并返回插入了laodAssets.js文件内容的html内容

首屏加载时间优化之在工作中实践

而要在什么地方才能获取到html内容呢?

恰好webpack的html-webapck-plugin插件中的htmlWebpackPluginAfterHtmlProcessing钩子中即可获取到html,如下脚本。

然后再在vue-config.js中配置这个自定义插件传入loadAssets.js的路径即可

首屏加载时间优化之在工作中实践

打包结果: 我们可以看到html文件中都有压缩好的loadAssets.js文件中的内容啦

首屏加载时间优化之在工作中实践

通过以上三次优化,我们再看看前后对比:

流程上:

多模板文件的请求少了两个,chunk文件的加载也移到了当前所需页面的请求后,并且200多个chunk缩减至10多个了。

首屏加载时间优化之在工作中实践

加载时间上:

前后提升了35%网络稳定的情况下1.7秒-2秒就能加载出来了。

与新后台对比:

新的加载时间为1.5-1.7秒左右,对比相差:0.3秒-0.5秒,刚好差不多是多模板加载的时间,那这样白屏时间已经优化成功啦!

四、拓展

这个优化到现在也已有三个月了,在这三个月中也因为这个优化出过一些小bug。其实对于这种webpack打包的项目优化,还是有一些需要注意的地方的。

1、使用MinChunkSizePlugin合并多个chunk文件的时候要注意项目中的多个页面的样式名不要重叠!!

因为在合并后报过好几个样式的bug因为有一些页面是直接在最外层覆盖组件库的样式在打包后就覆盖了在同一个chunk文件里的其他页面的样式了。

2、如果公司本身有调节升级成webpack5的也可以忽略这套方法,毕竟直接是webpack5就不需要进行这些操作。

五、总结

①确保先请求的是当前页面所需要的资源,而不是prefetch资源。

如果是prefetch资源在当前页面所需的资源前请求,先思考能不能通过自写脚本的方式延迟prefetch的资源加载,再看看能不能干掉prefetch。毕竟之前也提到了prefetch资源是会在空闲时间把剩下的资源,这样在切换页面或导航的时候就可以不用等待加载资源的时间啦

②要注意资源的请求不要太多,单个资源也不要太大,数量和大小要在一个适中值。

并发请求太多,TCP连接等待状态越长;资源大,下载时间过长。

③注意检查是否有进行一些不需要的请求,最大程度减少多余请求

④注意代码压缩