Skip to content

前端加载优化

很多时候我们都会想到减少 http 请求、压缩合并 js 以及 css、图片懒加载的技术、防止回流和重绘、css 放头部、js 放底部。以上的说法对吗?完全正确!可是在这个过程中,我觉得缺少一种思考。比如减少 http 请求,可以从哪些维度上减少呢?比如合并 http 请求?比如合并资源?比如图片懒加载?http 还有其他维度的优化吗?cookie 优化?http 请求和资源加载的区分优化?在 webview 中呢?和普通的浏览器的优化技术,又有什么区别?

对于这个问题,我喜欢这样回答

对于前面优化我们可以从这个方面去寻找优化的可能性与方案。如在我们访问一个页面的时候是下面这几个过程

输入 URL -> 判断是否存在当前 url 的缓存 -> 对域名进行 DNS 解析 -> 发送 TCP 链接 -> 发送当前页面地址的请求 -> 服务器返回数据进行响应

对于上面的流程我们可以对于

  1. 判断是否存在当前 url 的缓存

通过 nginx 等在服务器端对静态资源数据进行缓存配置

#缓存相应的文件(静态文件)
location ~ \.(gif|jpg|png|htm|html|css|js|flv|ico|swf)(.*) {
    proxy_pass http://cluster;         #如果没有缓存则通过proxy_pass转向请求
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_cache cache_one;
    proxy_cache_valid 200 302 1h;                              #对不同的HTTP状态码设置不同的缓存时间,h小时,d天数
    proxy_cache_valid 301 1d;
    proxy_cache_valid any 1m;
    expires 30d;                                         # 配置强缓存
}
  1. 对域名进行 DNS 解析

一般我们在优化的时候主要关注的是首页,所以这个没法优化,但是我们对于其他页面可以进行着一方面的优化

优化方法:检查页面是否添加了 DNS 预解析代码。

html
<link rel="dns-prefetch" href="//haitao.nosdn1.127.net" />

在移动端还可以使用 httpDNS(使用第三方 DNS 服务器直接获取当前域名对于的 IP 地址)、 域名收敛等手段优化 DNS 查询时间

  1. 发送 TCP 链接 -> 发送当前页面地址的请求 -> 服务器返回数据进行响应

下面就是建立 TCP 连接和请求获取对于的数据的过程,对于这个过程的优化就较多了

  • HTTP1.1 的长连接
Connection: Keep-alive
  • 长轮询、短轮询、websocket 的选择

  • HSTS

对于我们一个页面访问数据的时候,浏览器会对同一个域名的连接请求最大并行数进行限制(一般为 6),那我们一方面就需要减少 http 的请求数

  • 对于 JS 或者 css 文件我们可以通过 webpack 打包构建工具配置 splitChunks 去将一些通过的脚本函数打包到一个或者多个 chunks 中去,这样我们就可以不要在页面中去加载什么 cookie、date、axios 等第三方工具类

  • 对于图片等资源特别是图标这些小图片我们最好使用雪碧图将这些小图片合并成一张图片,然后通过 background-position 去处理。当然这是我们常用的一些方式,对于那些使用频率很小,或者可能就只在一个页面中用到的小图片,那么我们使用这种方式反而适得其反,这时候建议使用内联的方式,通过 webpack 将小图片转换成 base64 格式

  • 对于接口数据,我们也是尽量在首页等重要页面进行接口定制,将多个接口合并成一个接口。减少接口的请求次数

通过将不同的资源存放到不同的域名服务器下,突破浏览器连接请求最大并行数进行限制(域名发散),同时这个也有一个好处,也是我们对于 cookie 的优化

HTTP 是无状态的,那么对于我们网络用户登录等需要用户状态的操作怎么解决 HTTP 无状态的问题。这时候就可以通过 cookies,因为 cookies 信息会随请求在客户端和服务器之间传输。但是对于那些静态资源文件,其不需要获取用户的 cookie 信息,那么通过域名发散的方法,也可以减少静态资源请求的带宽数据

我们还可以压缩合并 js 和 css 数据

  • 通过 webpack 中的 minimizer 将我们的 js 和 css 进行混合压缩等,可以减少 js 和 css 的体积

在 nginx 中开启 gzip(移除图片的 gzip 压缩)

#压缩配置#
gzip  on;           #打开gzip压缩功能
gzip_min_length 1k; #压缩阈值
gzip_buffers 4 16k; #buffer 不用修改
gzip_comp_level 2;  #压缩级别:1-10,数字越大压缩的越好,时间也越长
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php  #压缩文件类型
gzip_vary off;      #跟Squid等缓存服务有关,on的话会在Header里增加 "Vary: Accept-Encoding"
gzip_disable "MSIE [1-6]\.";  #IE1-6版本不支持gzip压缩
  • 服务器发送响应环节,可以使用 Transfer-Encoding=chunked(bigPipe)
  • 减少 cookie 的体积(见上面的 cookie 的优化)

知识点

  1. preload

在当前页面中,你可以指定可能或很快就需要的资源在其页面生命周期的早期——浏览器的主渲染机制介入前就进行预加载,这可以让对应的资源更早的得到加载并使用,也更不易阻塞页面的初步渲染,进而提升性能

html
<link as="script" rel="preload" href="/xxxx.js">
  1. preconnect

元素属性的关键字preconnect是提示浏览器用户可能需要来自目标域名的资源,因此浏览器可以通过抢先启动与该域名的连接来改善用户体验 —— MDN

html
<link rel="preconnect" href="https://www.google-analytics.com">
  1. dns-prefetch

DNS-prefetch (DNS 预获取) 是尝试在请求资源之前解析域名。这可能是后面要加载的文件,也可能是用户尝试打开的链接目标 —— MDN

html
<link rel="dns-prefetch" href="https://www.google-analytics.com">
  1. prefetch

关键字 prefetch 作为元素 的属性 rel 的值,是为了提示浏览器,用户未来的浏览有可能需要加载目标资源,所以浏览器会事先获取和缓存对应资源,优化用户体验 ——MDN

html
<link rel="prefetch" href="/nest-page/js/xxx.js" crossorigin="anonymous" as="fetch">

参考

总结

  1. 减少 HTTP 请求数
  • webpack 打包构建工具配置 splitChunks
  1. 突破浏览器统一域名下并发数限制(域名发散)

  2. 合理设置 HTTP 缓存

  • 304 缓存

  • DNS 缓存

  1. 节流(压缩、合并)
  • 外部的脚本、样式进行合并(webpack 中的 minimizer )

  • cookie 大小

  • gzip

  1. 懒加载
  • 图片的懒加载

  • prefetch 资源的预加载

  • dns-prefetch