性能优化

写在前边: 前端的性能优化无非就是响应时间(不是接口响应时间,而是资源加载和页面渲染的时间),以下会简单描述下部分性能优化的方法

代码层面

  • 减少闭包(优化内存占用)
  • 减少注释和冗余变量(打包工具大部分均可配置插件)
  • 减少空格和多余换行,以及变量名压缩(打包工具可以处理)
  • 在http/1.x环境下,应该考虑分域名进行处理资源和接口请求,在谷歌下,对于同一个域名同时只能进行六个链接,所以建议分域名处理前端资源
  • 按需引用所需要的代码(部分打包工具在使用插件情况下也可以支持,类似rollup或者Snowpack原生就支持),不可否认某些dead code依旧可能打包,可以采用/*#_PURE_*/注释来解决
  • 长期不变的代码,类似运行库(vue、vuex、vue-router、pinia、react、react-dom之类的)可以打包成单个模块,可以更好利用缓存,减少资源请求
  • 部分资源合理利用cdn进行快速请求

传输阶段

尽可能减少请求资源的链路,分域名请求资源

  • gzip压缩代码,可以使用Nginx或者Apache服务器进行开启gzip压缩,前端如果有gz文件优先使用gz文件
  • 雪碧图、小于多少kb的直接内联代码中,不单独使用一个链接(webpack是有雪碧图插件的)
  • http/1.x 升级到http/2

cache (缓存)

强缓存

强制缓存就是直接从浏览器缓存查找该结果,并根据结果的缓存规则来决定是否使用该缓存的过程。

  • 不存在该缓存结果和标识,强制缓存失效,则直接向服务器发起请求(跟第一次发起请求一致)
  • 存在缓存结果和标识,但结果已失效,强制缓存失效,则使用协商缓存
  • 存在缓存结果和标识,并且结果未失效,强制缓存生效,直接返回该结果

控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Control优先级比Expires高。

协商缓存

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,有服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:

  • 协商缓存生效,返回304,服务器告诉浏览器资源未更新,则再去浏览器缓存中访问资源
  • 协商缓存失效,返回200和请求结果

同样,协商缓存的标识也是在响应报文的HTTP头和请求结果一起返回给浏览器的,控制协商缓存的字段分别有:Last-Modified/If-Modified-Since Etag/If-None-Match

其中Etag/If-None-Match优先级比Last-Modified/If-Modified-Since

强制缓存优先于协商缓存,若强制缓存生效则直接使用缓存,若不生效则进行协商缓存,协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存。

浏览器资源提示

浏览器的preloadprefetch区别就是,一个是当前页面就要用,另一个是下个页面可能会用到 详细介绍的文档地址https://www.w3.org/TR/resource-hints/#introductionopen in new window

Preload (预加载)

众所周知preload 是一个声明式 fetch,可以强制浏览器在不阻塞 document 的 onload 事件的情况下请求资源。预先加载资源,加载完毕直接执行。

比如场景: 某些网站中会用到字体,字体一般内嵌入css样式表,表现形式为

/* font.css */
@font-face: {
    font-family: 'YaHei Consolas Hybrid';
    src: url('xx/xx/x/xx/xx.ttf');
}

那么加载结束后就是加载font.css然后在onload后加载xx/xx/x/xx/xx.ttf,在没有加载出字体前,浏览器一般会进行降级处理,诚然现在的网络环境很好了,但是不排除部分用户网络环境依旧不佳,在网络不佳情况下,加载完页面后,如果有字体加载进来,会进行闪烁后进行字体的更换,体验并不佳,这时候可以直接在head标签内采用预加载

<link src="xx/xx/x/xx/xx.ttf" rel="preload" as="font" type="font/ttf"/>

这样操作之后,不会阻塞document的document加载,并且可以将请求提到最前,大部分场景下,初次渲染时,字体就以加载完毕

Prefetch (预获取)

Prefetch 告诉浏览器这个资源将来可能需要,但是什么时间加载这个资源是由浏览器来决定的。大概率即将被访问到的资源可以使用prefetch提升性能和体验!

prefetch在大多数浏览器中都是晚于onload生命周期的

使用场景: 用户下个页面为二级页面,并且有些细碎的资源请求,或者一些常规图片,可以在一级页面添加上下个页面的资源请求,当然也要慎用,这样用户的体验会更较为顺滑

dns-prefetch (预解析)

即将进行解析的域名进行获取,在对该域名资源请求前进行dns解析,加快请求时的dns解析速度

场景:在一个系统中有多个子域名服务,例如在阿里云官网中会跳转一些服务,

<link rel="dns-prefetch" href="//query.aliyun.com">
<link rel="dns-prefetch" href="//gm.mmstat.com">

Preconnect(预连接)

preconnect链接关系类型用于指示将用于获取所需资源的来源。启动早期连接,包括 DNS 查找、TCP 握手和可选的 TLS 协商,允许用户代理掩盖建立连接的高延迟成本。。

可以用在以下场景: 你的资源有cdn资源,并且马上会用到,或者大概率要跳转别的连接页面,比如友链,或者按钮就是跳转网址,可以这么处理,但是兼容并不太好,但也可以使用,尚处于实验性质(2022-05-02编辑)

<link rel="preconnect" href="//example.com">
<link href="https://cdn.domain.com" rel="preconnect" crossorigin>
Last Updated: