性能优化作为一个老生常谈的话题,可以在网上查到各种零碎的优化点,但对于新手来说,要对项目做完整的性能优化,却不知从何下手,其根本是缺乏对性能知识体系的认识
性能优化准则
-
不宜过早优化
在典型的互联网开发模式中,追求的是快速的迭代和试错,过早的优化往往会成为一种无用功
-
不宜过度优化
在项目运营的不同阶段,对系统的性能体验都会有不一样的要求,在能够满足使用预期的情况下,就没有必要花费时间精力去做优化
为什么做性能优化
-
用户体验金字塔
从 2018 年 Google I/O 大会上提供的数据发现,页面加载时长是影响用户体验的最大因素
-
性能优化业务价值
页面加载时长不仅对用户体验有影响,还对业务数据有影响,当页面加载时长超过
5s
就会造成90%
的用户流失
如何建立性能知识体系
既然性能体验优化是非常有价值的,那么如何能很好地串联起零碎的优化策略点并形成知识体系呢?我们从一道经典的面试题入手:
浏览器从输入地址到页面显示的过程中发生了什么?
1、浏览器对输入的地址进行 URL
解析
2、缓存解析,如 浏览器缓存、系统缓存、路由器缓存
等
3、通过 DNS
服务器将主机域名转换为 IP
地址
4、根据 IP
地址找到对应的服务器,发起 TCP
连接
5、建立 TCP
连接后,发起 HTTP
请求
6、服务器响应 HTTP
请求,浏览器获得 HTML
代码
7、浏览器解析 HTML
代码,再请求代码中的资源,如 CSS、JS、图片
等
8、浏览器解析渲染视图页面
9、服务器断开 TCP
连接
从整个页面渲染的链路中,可以提取关键词:URL解析
、DNS解析
、HTTP协议
、HTTP缓存
、TCP连接
、服务器
、响应体
、渲染
,根据这些关键词产出性能优化策略
渲染链路:URL解析
-
地址解析和编码
在浏览器地址栏中输入 URL 后,浏览器会解析输入的字符串,如果是 URL 就进行编码
encodeURI()
和decodeURI()
编码函数只把参数中的空格
编码为%20
,汉字进行编码,其余特殊字符不会转换encodeURIComponent()
和decodeURIComponent()
编码方法还会对:/
进行编码,所以不能用它来对网址进行编码,只合适对 URI 中的参数进行编码和解码 -
安全协议HSTS
HSTS
(HTTP Strict TransportSecurity)是一种新的Web
安全协议,其作用是强制客户端使用HTTPS
协议与服务器创建连接,浏览器会自动将输入带有 http 的地址转写成 https 直接发送请求
渲染链路:DNS解析
-
概述
计算机之间网络通信只认
IP
地址,所以域名和IP
地址之间的转换工作被称之为域名解析
-
关联优化
渲染链路:HTTP1.1协议
-
概述
超文本传输协议,是互联网应用最为广泛的一种网络协议,它规范了浏览器和服务器的数据通信规则
其灵活性,允许传输任意类型的数据对象,使用
Content-Type
加以标记即可Content-Type: application/x-www-form-urlencoded
Object.keys(data).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`).join('&')
form 表单的提交形式,提交的数据按照
key1=val1&key2=val2
的方式进行编码,key
和val
都进行了URL
转码Content-Type: multipart/form-data
用于 form 表单上传文件,如果使用
new FormData()
的形式上传文件,则Content-Type
字段不需要指定任何值,否则会造成数据传输不成功Content-Type: application/json
JSON.stringify(data)
告诉服务端消息主体是序列化后的 JSON 字符串,由于 JSON 规范的流行,这种方式使用的越来越多
-
关联优化
渲染链路:HTTP2协议
-
协议概述
HTTP2
为HTTP
协议提供了优化传输,它支持HTTP1.1
的所有核心功能,但旨在以多种方式提高效率 -
协议特性
二进制传输
将请求和响应的数据分割为更小的帧,并对它们采用二进制编码
头部压缩
头部
headers
是以纯文本传输且请求越多导致消耗在头部的流量就越多,尤其是每次都要传输User-Agent
和Cookie
这类不会频繁变动的内容,完全是一种浪费1、维护一份相同的静态字典
Static Table
,包含常见的头部名称,以及特别常见的头部名称与值的组合2、维护一份相同的动态字典
Dynamic Table
,可以动态地添加内容多路复用
使用同一个连接传输所有的并行请求和响应,而交错的多个并行请求响应却不受阻塞影响
服务器推送
为单个客户端请求发送多个响应的能力
渲染链路:HTTP缓存
-
缓存过程分析
浏览器与服务器的通信方式为应答模式,即:浏览器发起HTTP请求 -> 服务器响应该请求
由图可得:
1、浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识
2、浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中
-
强制缓存
通过
Expires
和Cache-Control
两个响应头字段来控制,如果同时存在,则后者优先级高于前者HTTP1.0标准
Expires: Mon, 06 Apr 2020 12:08:42 GMT
使用客户端时间和服务端返回的时间做对比,容易产生误差HTTP1.1标准
Cache-Control: max-age=3600
时间单位为秒,表示 1 小时符合强制缓存策略时,使用本地的缓存,不再向服务器发送请求,状态为
Status Code: 200 OK (from disk cache)
或Status Code: 200 OK (from memeory cache)
-
协商缓存
通过
Last-Modified
和Etag
两个响应头字段来控制,如果同时存在,则后者优先级高于前者Last-Modified: Wed, 25 Mar 2020 08:33:53 GMT
Etag: "5e7b16bd-a0ba"
资源文件的唯一标识,由服务器生成强制缓存失效后,浏览器携带缓存标识(If-Modified-Since / If-None-Match)向服务器发起请求,如果文件未修改过,可继续使用本地缓存,状态为
Status Code: 304 Not Modified
-
清除缓存
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
no-store
完全禁止缓存,用于某些变化非常频繁的数据no-cache
可以在客户端缓存资源,但每次都需要向服务端去做新鲜度校验,来决定从服务端获取新的资源(200)还是使用客户端缓存(304)在客户端发送 GET 请求时也可通过添加时间戳参数来禁用缓存
渲染链路:TCP连接
-
建立TCP连接
通过三次握手,客户端与服务器利用
SYN
报文段交换彼此的初始序列号,互相维持一个具有连接特性的状态
-
客户端发起HTTP请求 && 服务端响应请求
-
关闭TCP连接
通过四次挥手,确保数据传输的完整性,当被动方的数据全部传输给主动方后进行连接的关闭
渲染链路:CDN服务器
-
CDN作用
完成
TCP
连接后,进入服务器响应。对于静态资源,可以接入CDN
服务器来有效地 提升网站的稳定性,大大地缩减资源加载时间 -
CDN图示
渲染链路:响应体压缩
-
GZIP压缩
服务器返回响应体,其内容未经压缩的话,体积往往比较大,可以采用
GZIP
压缩来 大大的缩减文本类的资源体积,而对于图片资源则效果不大 -
GZIP原理
GZIP
采用的是LZ77
和哈夫曼
算法,都是针对文本类的压缩算法 -
GZIP压缩标识
响应头字段中包含
Content-Encoding: gzip
表示已经开启压缩
渲染链路:解析渲染页面
-
解析渲染流程
1、根据
HTML
解析出DOM
树2、根据
CSS
解析出CSS
规则树3、结合
DOM
树和CSS
规则树,生成渲染树4、根据渲染树计算
DOM
节点的信息(节点的大小、位置)5、根据计算好的信息绘制页面(CSS的颜色、背景、字体等)
-
解析渲染图示
-
一起交流学习
加群交流请看 沸点