前端性能优化总结
1. 基础知识
1.1浏览器输入url到显示页面,发生了什么?
整个过程可分为如下几个阶段:
- DNS 解析:将域名解析为对应的 IP 地址(👉图解DNS服务器解析过程)
- TCP 连接:主机与服务器建立连接(👉一文弄懂TCP连接)
- HTTP 发出请求
- 服务器处理请求,返回HTTP响应
- 浏览器接受响应数据,解析渲染页面
1.2 优化思路
-
网络层面优化
前端对 DNS解析 与 TCP连接阶段优化能力有限,主要考虑 HTTP请求响应的优化,包括两个思路:
- 减少请求次数:使用CSS精灵合成图片
- 减少单次请求耗时:利用缓存策略可减少响应数据大小,压缩图片
特点:源文件中没有页面完整内容
-
渲染层面优化
-
客户端渲染
服务端把渲染需要的静态文件(CSS、js、image等)发送给客户端,客户端在浏览器加载相应文件(加载css、运行 js等)生成DOM
-
服务端渲染
由服务器把需要的组件或页面渲染成 HTML 字符串,然后把它返回给客户端。客户端拿到手的,是可以直接渲染然后呈现给用户的 HTML 内容,不需要为了生成 DOM 内容自己再去跑一遍 JS 代码
特点:所见即所得,查看页面源码可以看到完整内容
因此网站会出于效益(seo)的考虑才启用服务端渲染,而非性能
另外,服务端渲染解决了一个非常关键的性能问题——首屏加载速度过慢
* 除非网页对性能要求太高,尝试所有方法无果,才考虑此方案
- 优化思路图
2. 网络层面优化
2.1 HTTP请求优化
- 合并图片,利用CSS -background-position调整图片显示位置
- 压缩品质要求不高的图片
- 选择适合的图片格式
- 浏览器缓存:缓存 css/js/image 等比较固定的文件
- 不同图片格式对比
格式 | 特点 | 缺陷 | 使用场景 |
---|---|---|---|
jpg | 有损压缩、体积小、加载快 | 不支持透明格式 | 背景图、轮播图 、 (复杂,色彩丰富的图片) |
png | 无损压缩、支持透明、色彩丰富 | 体积太大 | 小logo、颜色简单对比强烈的图 |
gif | 支持动态图 | 颜色少 | 动态图 |
svg | 文本文件、体积小、不失真、兼容性好 | 可直接写入或引入html文件 | |
Base64 | 文本文件 | 不可用于css精灵 | 小图标 |
WebP | 支持透明、动态、丰富细节 | 兼容性一般 | 全能(Google开发) |
2.2 Web缓存(HTTP缓存)
-
思维导图
-
缓存过程分析
-
浏览器与服务器通信的方式为应答模式,即是:浏览器发起HTTP请求 – 服务器响应该请求。
-
浏览器第一次向服务器发送请求得到响应后,会根据响应报文中HTTP头的缓存标识,决定是否缓存结果。
-
浏览器每次发起请求都会先在浏览器缓存中查找该请求的结果以及缓存标识。
-
浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中。
-
浏览器缓存可分为强制缓存和协商缓存。
-
-
强制缓存
控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Conctrol的优先级比Expires高。
字段 HTTP版本 取值 备注 expires 1.0 缓存到期时间(与客户端时间对比) 客户端与服务器时间可能不一致导致缓存失效 cache-control 1.1 private(默认值):所有内容仅客户端可缓存
public:所有内容都可缓存(客户端与代理服务器)
no-cache:客户端缓存,验证协商缓存
no-store:不缓存
max-age=xxx:缓存内容xxx秒后失效优先级高于expires -
协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:
- 协商缓存生效,返回304
- 协商缓存失败,返回200和请求结果
控制协商缓存的字段分别有:Last-Modified / If-Modified-Since和Etag / If-None-Match,后者优先级更高。
- Last-Modified
是服务器响应请求时,返回该资源文件在服务器最后被修改的时间 - If-Modified-Since
是客户端再次发起该请求时,携带上次请求返回的Last-Modified值 - Etag
是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成) - If-None-Match
是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值
二者对比
- 优先级:Etag 优先级更高
- 精确度:Etag 高,Etag 每次改变都会生成,而 Last-Modified 记录时间单位是秒,一秒内多次改变将无法记录
- 性能:Last-Modified 更佳,它只需记录时间,而 Etag 需要计算一个 hash 值
-
浏览器缓存图示
2.3 Web 缓存(浏览器缓存)
- 本地存储小容量:cookie、localStorage、sessionStorage
- 本地存储大容量:IndexDB(用于邮箱、在线编辑等场景)、WebSQL(W3C启用)
- 应用缓存与PWA
- 往返缓存
3. CDN
3.1 概念
- CDN(Content Delivery Network,即内容分发网络)指的是一组分布在不同地区的服务器。
- 服务器存储这数据副本,会就近响应用户请求
- CDN 可提升首次请求速度
- 两个核心功能:缓存与回源
- 缓存是说我们把资源 copy 一份到 CDN 服务器上这个过程
- 回源是说 CDN 发现自己没有这个资源(一般是缓存的数据过期了),转头向根服务器(或者它的上层服务器)去要这个资源的过程。
3.2 CDN 与前端性能优化
- CDN 往往被用来存放静态资源( JS、CSS、图片等不需要业务服务器进行计算即得的资源)。
- “根服务器”本质上是业务服务器,CDN 服务器则像一个仓库,它只充当资源的“栖息地”和“搬运工”。
- 许多一线的互联网公司,“静态资源走 CDN”并不是一个建议,而是一个规定。
4. 渲染层面优化
4.1 浏览器渲染
-
浏览器内核
可分成两部分:渲染引擎(Layout Engine 或者 Rendering Engine)和 JS 引擎。
渲染引擎又包括了 HTML 解释器、CSS 解释器、布局、网络、存储、图形、音视频、图片解码器等等零部件。 -
浏览器渲染过程图示
-
基于渲染流程的 CSS 优化建议
1. CSS选择符匹配规则: 从右往左依次遍历
- 避免使用通配符,按需选择
- 注意继承属性,避免重复定义
- 少用标签选择器,尽量用类选择器替代
- id 和 class 选择器不要再增加多余的选择器
- 减少嵌套,后代选择器开销大
2. CSS 阻塞
默认情况下,浏览器会等待 CSSOM 构建完成后才开始渲染页面(即DOM解析完成CSSOM未完成,不会渲染页面)
CSS 是阻塞渲染的资源。需要将它尽早(CSS 放在 head 标签)、尽快(CDN)地下载到客户端,以便缩短首次渲染的时间。3. JS 阻塞
JS 引擎是独立于渲染引擎存在的。 当 HTML 解析器遇到一个 script 标签时,它会暂停渲染过程,将控制权交给 JS 引擎。
-
JS 加载的三种方式
正常模式:阻塞,等待 js 文件加载和执行完成,才继续其它任务
async 模式:异步加载,执行过程仍会阻塞
deffer 模式:延缓,异步加载,DOM 解析完成,DOMContentLoaded 事件即将被触发时执行- async 与 deffer对比
- 两者都不会阻止 document 的解析
- defer 会在 DOMContentLoaded 前依次执行 (可以利用这两点哦!)
- async 则是下载完立即执行,不一定是在 DOMContentLoaded 前
- async 因为顺序无关,所以很适合像 Google Analytics 这样的无依赖脚本
-
加载方式选择
- js 文件是独立的模块且不依赖任何js,使用 async;
- js 文件依赖其他 js 或者被其他 js 依赖,使用 defer;
- js 文件很小且被 async script 依赖,使用正常模式的script且放在async script 前面
4.2 DOM 优化
-
重绘与重排
重绘:是一个元素外观的改变所触发的浏览器行为,例如改变visibility、outline、背景色等属性(上面说到的其他属性)。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随重排。
重排:当DOM的变化影响了元素的几何属性(宽或高),浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为重排。重排一定伴随着重绘。
-
优化建议
1、查找元素的优化。尽量使用 ID 或者类来查找元素,避免用属性来查找元素。
2、减少访问和改变DOM元素,包括添加,修改,删除DOM。改变DOM就会引起浏览器渲染。
3、减少改变DOM的样式类等。改变DOM元素的样式,类也会导致浏览器渲染。
4、最小化重绘和重排方法:
(1)隐藏元素,进行修改,然后再显示它。
(2)将原始元素拷贝到一个脱离文档的节点中,修改副本,然后覆盖原始元素。
5、减少 iframe 使用,iframe 需要消耗大量的时间,并阻塞下载。
6、使用事件委托,减少绑定事件的数量。
7、多次访问同一DOM,应该用局部变量缓存该DOM。