每天一点面试题(18)------首屏加载时间的优化策略



          • 1、尽可能的缩小webpack或者其他打包工具生成的包的大小
          • 2、使用服务端渲染的方式
          • 3、使用预渲染的方式
          • 4、使用gzip减小网络传输的流量大小
          • 5、按照页面或者组件分块懒加载
          • 6、代理缓存
          • 7、使用CDN
          • 8、添加Expires头
          • 9、压缩组件
          • 10、代理缓存

1、尽可能的缩小webpack或者其他打包工具生成的包的大小 为了做到这一点,需要做到尽可能的减少生产环境下依赖的库数量,尽可能的按需引用,减少无用代码占的空间。
我刚开始优化的时候,就不知道从何处优化起,而且根本不知道生成的包中哪个依赖占据着空间,我还一度挨个删去库引用,来看哪个库占用的空间最多。 后来才知道有名叫:webpack-bundle-analyzer的分析工具,接下来我顺带总结一下这个包的使用姿势。
: 首先
npm install --save-dev webpack-bundle-analyzer

然后在webpack.prod.conf.js中配置:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; plugins: [ new BundleAnalyzerPlugin( { analyzerMode: 'server', analyzerHost: '127.0.0.1', analyzerPort: 8888, // 运行后的端口号 reportFilename: 'report.html', defaultSizes: 'parsed', openAnalyzer: true, generateStatsFile: false, statsFilename: 'stats.json', statsOptions: null, logLevel: 'info' } ), ]

配置就完成了,正常npm run build 结束后,就会自动打开一个打包生成文件的模块组成图在默认浏览器中,图中面积大的就是占据空间大的模块。
官方文档上还需要安装babel-plugin-component插件才能使局部引用
2、使用服务端渲染的方式 这个服务端渲染不同于后端渲染,服务端渲染只是把当前的前端框架中的一部分js代码放到服务器上渲染,加载到浏览器上的html就不是一个空页面,这样可以减少首页的白屏时间,同时提高被搜索引擎检索的机会。
但是这个服务端渲染有不少的局限,例如它的服务端必须依靠node服务器,不进行服务端渲染方式的只需要一个普通的静态服务器就可以了。还有,vue官方的ssr配置异常的复杂,需要花不少的时间,踩不少的坑,如果开发时使用的vue-cli的话,改用服务端渲染会很麻烦。如果必须要使用服务端渲染的话,最好刚开始就使用基于vue的nuxt.js脚手架去开发,会减去繁琐的配置过程。
3、使用预渲染的方式 这个预渲染的方式简单来说就是在正常打包时,会预先运行一次js代码,将一部分静态的页面直接渲染成html写在生成的index.html中,这种方式在加载完index.html后,就会有界面展示出来,无需等待加载js代码后再去渲染,所以这种方式也可以显著的减少首屏加载时间,也可以提高被搜索引擎检索的机会,同时预渲染的配置很简单,容易上手。
缺点是在需要预渲染的页面较多时,build打包的时间会十分漫长。
预渲染的工具有这些:
prerender-spa-plugin.
react-snap.
snapshotify.
presite.
这里还有这几个预渲染插件的各种比较.
我比较喜欢预渲染这种优化方式,很简单有效,几乎不需要什么配置。这几种插件的基本原理都是本地运行指定的js代码,然后将空头浏览器渲染出的页面写入指定的h5文件。
但是我自己在做项目的时候,出现了各种各样的问题。在打包时报出各种各样的错误,解决了一个又出一个,把这几个插件都试了一遍,依然没有成功预编译出一个满意的页面效果,当然这是我个人的问题,与这几个轮子没有关系。
最后,我想出了一种“土”办法,就用自己的浏览器去预渲染页面。
在浏览器上打开需要预渲染的页面,然后点击右键选择另存为,将文件保存下来,就得到了“预渲染”的html文件。
如果觉得里面的css代码量太大,推荐使用chrome的一个插件 css used, 下载安装之后,在开发者工具中的element中,与style选项并排的就有一个css used选项,点击后就会加载出这个页面用到的css界面,过滤掉了没有用到的css代码,将有用的css代码替换掉原本html里面的css代码即可。
最后,需要将打包生成的js和css代码的路径添加到html里面(就像打包生成的index.html一样),这样,在这个html加载完成后,就可以显示一个预渲染的页面了,等到依赖的js和css加载完成后,会有新的代码覆盖掉预渲染的页面。
我的这种“土”办法实属无奈,但依旧有效,成功的将首屏加载时间缩短了50%。用这种方法也可以自己制作一个骨架预渲染界面,在等待加载js和css时,界面上只显示一个页面的大体框架,比全白屏的交互体验要好的多。
4、使用gzip减小网络传输的流量大小 gzip是GNUzip的缩写,最早用于UNIX系统的文件压缩。HTTP协议上的gzip编码是一种用来改进web应用程序性能的技术,web服务器和客户端(浏览器)必须共同支持gzip。目前主流的浏览器,Chrome,firefox,IE等都支持该协议。常见的服务器如Apache,Nginx,IIS同样支持gzip。使用gzip可以将原静态文件压缩到30%,效果很明显,对于优化首屏加载时间非常适合。
这种优化实现特别简单,只需要配置一下自己使用的服务器就可以了。
以我使用的nginx服务器的配置为例:
http { includemime.types; default_typeapplication/octet-stream; sendfileon; keepalive_timeout65; proxy_buffering on; # 开启gzip gzip on; # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩 gzip_min_length 1k; # gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间 gzip_comp_level 2; # 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。 gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml; # 是否在http header中添加Vary: Accept-Encoding,建议开启 gzip_vary on; # 禁用IE 6 gzip gzip_disable "MSIE [1-6]\."; server { listen80; server_namelocalhost; location /{ alias /; proxy_connect_timeout 1; proxy_send_timeout 30; proxy_read_timeout 60; # 这里反向代理到本地的开发服务器上 proxy_pass http://localhost:8080/; } } }

这样就开启了gzip。
5、按照页面或者组件分块懒加载 这种优化,就是将每个组件的js代码独立出来,在使用到这个组件时,才向服务器请求文件,并且请求过一次后就会缓存下来,再次使用到这个组件时,就会使用缓存,不再发送请求。
配置很简单,只需要在vue-router中添加一些简单的配置即可。
import Vue from 'vue' import Router from 'vue-router'Vue.use(Router); export default new Router({ mode: 'history', linkActiveClass: 'router-link-active', routes: [ { path: '/', // 这里只需要把原来从外部引入的组件换成以下的语句就可以了 component: resolve => require(['../components/(你的组件)'], resolve) }, ] })

其他地方不需要进行任何修改,打包后就会发现js文件数量比原来不分块加载的多了不少。
6、代理缓存 当浏览器通过代理来发送请求时,情况会不一样。假设针对某个URL发送到代理的第一个请求来自于一个不支持gzip的浏览器。这是代理的第一个请求,缓存为空。代理将请求转发给服务器。此时响应是未压缩的,代理缓存同时发送给浏览器。现在,假设到达代理的请求是同一个url,来自于一个支持gzip的浏览器。代理会使用缓存中未压缩的内容进行响应,从而失去了压缩的机会。相反,如果第一个浏览器支持gzip,第二个不支持,你们代理缓存中的压缩版本将会提供给后续的浏览器,而不管它们是否支持gzip。
解决办法:在web服务器的响应中添加vary头Web服务器可以告诉代理根据一个或多个请求头来改变缓存的响应。因为压缩的决定是基于Accept-Encoding请求头的,因此需要在vary响应头中包含Accept-Encoding。
7、使用CDN 如果应用程序web服务器离用户更近,那么一个HTTP请求的响应时间将缩短。另一方面,如果组件web服务器离用户更近,则多个HTTP请求的响应时间将缩短。
CDN(内容发布网络)是一组分布在多个不同地理位置的Web服务器,用于更加有效地向用户发布内容。在优化性能时,向特定用户发布内容的服务器的选择基于对网络慕课拥堵的测量。例如,CDN可能选择网络阶跃数最小的服务器,或者具有最短响应时间的服务器。
CDN还可以进行数据备份、扩展存储能力,进行缓存,同时有助于缓和Web流量峰值压力。
CDN的缺点:
1、响应时间可能会受到其他网站流量的影响。CDN服务提供商在其所有客户之间共享Web服务器组。
2、如果CDN服务质量下降了,那么你的工作质量也将下降
3、无法直接控制组件服务器
8、添加Expires头 页面的初次访问者会进行很多HTTP请求,但是通过使用一个长久的Expires头,可以使这些组件被缓存,下次访问的时候,就可以减少不必要的HTPP请求,从而提高加载速度。
Web服务器通过Expires头告诉客户端可以使用一个组件的当前副本,直到指定的时间为止。例如:
Expires: Fri, 18 Mar 2016 07:41:53 GMT
Expires缺点: 它要求服务器和客户端时钟严格同步;过期日期需要经常检查
HTTP1.1中引入Cache-Control来克服Expires头的限制,使用max-age指定组件被缓存多久。
Cache-Control: max-age=12345600
若同时制定Cache-Control和Expires,则max-age将覆盖Expires头
9、压缩组件 从HTTP1.1开始,Web客户端可以通过HTTP请求中的Accept-Encoding头来表示对压缩的支持
Accept-Encoding: gzip,deflate
如果Web服务器看到请求中有这个头,就会使用客户端列出来的方法中的一种来进行压缩。Web服务器通过响应中的Content-Encoding来通知 Web客户端。
Content-Encoding: gzip
10、代理缓存 当浏览器通过代理来发送请求时,情况会不一样。假设针对某个URL发送到代理的第一个请求来自于一个不支持gzip的浏览器。这是代理的第一个请求,缓存为空。代理将请求转发给服务器。此时响应是未压缩的,代理缓存同时发送给浏览器。现在,假设到达代理的请求是同一个url,来自于一个支持gzip的浏览器。代理会使用缓存中未压缩的内容进行响应,从而失去了压缩的机会。相反,如果第一个浏览器支持gzip,第二个不支持,你们代理缓存中的压缩版本将会提供给后续的浏览器,而不管它们是否支持gzip。
【每天一点面试题(18)------首屏加载时间的优化策略】解决办法:在web服务器的响应中添加vary头Web服务器可以告诉代理根据一个或多个请求头来改变缓存的响应。因为压缩的决定是基于Accept-Encoding请求头的,因此需要在vary响应头中包含Accept-Encoding。
vary: Accept-Encoding

    推荐阅读