前端性能优化----网络篇
前端性能优化—-网络篇
基础知识
DNS
DNS 过程:浏览器(cache) ==> 操作系统(hosts) ==> ISP
三次握手
SYN: 同步信号, ACK: 知道, FIN: 说完了
Round1: A发送SYN(x)给B
Round2: B发送ACK(x+1)和SYN(Y)给A
Round3: A发送ACK(y+1)给B
第三次握手的必要性:前两次结束说明A能发,B能收,B能发,需要最后A发送ACK(y+1)这样B才能知道A能收
三次握手成功之后就可以发送HTTP内容了
四次挥手
也可能B先发FIN(x)给A
Round1: A发送FIN(x)给B
Round2: B发送ACK(x+1)给A
这两次挥手结束B就知道了A说完了
Round3之前B还有可能会继续说话,因为B知道A说完了,但是B可能还没有说完
Round3: B发送FIN(y)给A
Round4: A发送ACK(y+1)给B
Round4之后A也知道B说完了
为什么四次挥手中间两次不能合并? 因为Round2和Round3之间B还可能有话要说
HTTP 请求和响应
可以使用WireShark抓包查看请求
浏览器基本原理
JS的下载和执行会阻塞HTML的解析
JS的下载会阻塞HTML的解析, 因为JS是一行一行解析的,解析到<script>标签就必须等到JS下载完毕JS的执行会阻塞HTML的解析, 因为JS可能会改变DOM的结构(使用诸如document.write(<p>你好</p>)等API)
async和defer的区别
defer下载JS不会影响HTML解析,并且保证JS执行在HTML解析之后,DOM ready之前多个
defer执行顺序按照代码书写顺序来async下载JS完全和HTML解析没关系,执行顺序在DOM ready之前还是之后是不确定的多个
async执行顺序也是不确定的
CSS的解析会阻塞JS的执行
CSS的解析会不影响JS的下载JS的执行需要读取CSS解析结果,所以得等到CSS的解析完毕才能执行JSJS执行前要确保CSS的下载和解析都完毕
- 布局、绘制、合成(Layout, Paint, Composite)
布局解决大小尺寸等问题(位置)
绘制解决颜色阴影问题(外观)
合成解决层次问题(图层)
更新阶段:Layout ==> reflow Paint ==> repaint
那些属性操作会触发
reflow和repaint可以查看CSS Triggers
Chrome 浏览器工具
Network面板:查看页面时间线Performance面板:查看JS性能Rendering面板:查看页面渲染Coverage面板:查看代码使用率Lighthouse面板:查看优化建议
Network面板单个请求Waterfall的Waiting(TTFB)时间很长就和浏览器没什么关系,要么是服务器太慢,要么是用户带宽不够
优化
Web
性能指标,参考
连接的复用与并行化
DNS prefetch
假设index.html的部分代码为
1 |
|
上述情况,浏览器会按顺序做如下事情:
DNS解析a.com下载并执行
1.jsDNS解析b.com下载并执行
2.js
使用prefetch可以将步骤1和步骤2合并
使用prefetch修改如下
1 | <!-- 在index.html的head里写 --> |
TCP连接复用
HTTP请求头加Connection: keep-alive,响应头会返回相同字段内容
HTTP请求头加KeepAlive: timeout=5, max=100 表示如果你5s还不发起请求我就关闭TCP连接,并且最多服用100次,再来我就关闭TCP连接,重新TCP
流程,,响应头可能会返回不同字段内容,此时要以服务器返回为准
HTTP/1.1不需要自动有的
- 并行化连接
和TCP连接复用类似,TCP连接复用是串行的,而并行化连接是并行的
并行连接个数会受到浏览器限制,不同浏览器上线不同,Chrome最新浏览器允许同时并行6个请求
此时还可以通过将12个资源分别放在两个域名下同时请求,将会一次请求得到12个结果,浏览器并没有限制不同域名的个数
复用和并行是不冲突的
HTTP管道化
HTTP/2的多路复用与ServerPush
HTTP/1.1是基于字符串的,HTPP/2是基于帧Frame(二进制)的帧
Frame由9个固定字节(Lenght+Type+Flags+StreamID)加上最大16M字节的数据payload构成的请求头和响应头会被发送方进行压缩,分成几个连续的帧传输
HTTP/2的多路复用中的路实际是流的概念,通过流承载的是帧HTTP/2的多路复用中的每条路上只能有一次请求和响应,每条路互不影响,响应和请求通过StreamID一一对应流也是可以复用的,但是多路是更广阔的范畴,相当于以前在一条路上进行并行或者复用,现在直接多了很多条路
案例分析 https://www.qq.com/
服务端推送ServerPush
需要后端配置,比如nginx配置的location配置http2_push
1 | location / { |
Cookie Free & CDN
资源合并:CSS Sprites、Icon Font、SVG Symbols
Webpack提供有CSS Sprites工具资源内联:Inline Resource
小图片通过
data URL内联小
CSS文件嵌入<style>标签小
JS文件<script>标签Webpack提供有url-loader,html-webpack-plugin等工具资源压缩:
gzip、nginxNginx, Apache, NodeJS
1
2
3
4gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/xml;代码精简
HTML ==> 删空格,删闭合
CSS ==> 删未用
JSS ==> 改名,tree shaking
SVG ==> 删无用标签属性
Image ==> 减小体积(有损/无损)
使用
Webpack相关插件都可以实现减小
Cookie体积Cookie体积上限:4Kb如何实现
cookie-free? 尽量不要用cookie, 启用新域名CDN 的原理和实施
CDN: 内容分发网络,从物理意义上缩短距离,加快速度DNS负载均衡:DNS解析域名的时候会返回不同的IP如何将文件发送到
CDN? 使用命令行将文件上传到CDN服务器优点:
cookie-free
并行请求/多路复用
下载速度快(只处理静态文件)
缺点:
付费
部署复杂
可控性差
跨域 CORS
CDN 会出现什么样的跨域问题?
Canvas虽然可以加载跨域图片,但是在调用getImageData(),toBlob(),toDataURL()时会产生报错,解决办法是启CORS头,并给图片添加crossorigin=anonymous
属性。详见 MDNwindow.addEventListener('error', ...)无法捕获跨域JS的错误详情。解决办法有两个,一个是启用CORS头并给script标签添加crossorigin=anonymous
属性,另一个比较开脑洞,是重写addEventListener,详见《解决 “Script Error” 的另类思路》
gzip和gzip_static有什么区别?
Nginx实际上提供了两种gzip模式gzip on;和gzip_static on;前者会在每次请求时压缩文件,有一点浪费
CPU
而后者会在遇到/path/to/file请求时,主动寻找/path/to/file.gz作为压缩版本,找不到就直接返回未压缩的版本
缓存和内容协商
Cache-Control
HTTP响应可以要求浏览器将文件缓存一段时间,具体写法为:Cache-Control: public, max-age=3600, must-revalidate其中
max-age: 3600表示最长缓存时间为3600秒,public表示网络中的中间设备(如代理)也可以缓存此内容,must-revalidate表示缓存过期后不能再使用,必须重新校验(重新校验过程也叫内容协商)。
在未来的3600秒内,浏览器对于相同URL的请求,一律不发出,且直接使用缓存作为其响应内容协商
主要是协商过期之后能重用吗?
内容协商过程如下:
- 浏览器第一次访问资源时,服务器除了添加缓存之外,还会计算出资源的哈希值,附加在响应头里,写法为
ETag: W/"7f9239ce726764aa22093884902e018d"(ETag是实体标签) - 在有效期内,浏览器不会再对相同的URL发出请求
- 等待有效期结束后,浏览器再次请求同一资源,但是会在请求头附上:
If-None-Match: W/"7f9239ce726764aa22093884902e018d" - 服务器收到请求后,发现同一资源的哈希值和浏览器附带的哈希值一样,说明资源没变,就会返回
304(Not Modified) - 如果发现资源哈希值不同,说明文件发生了变化,就会返回
200,并将最新文件内容返回
- 浏览器第一次访问资源时,服务器除了添加缓存之外,还会计算出资源的哈希值,附加在响应头里,写法为
新旧两套方案
http版本 缓存 内容协商 HTTP 1.1 Cache-Control: public, max-age=3600, must-revalidate
ETag: W/“7f9239ce726764aa22093884902e018d”请求头:If-None-Match: W/“7f9239ce726764aa22093884902e018d”
响应: 304+空/200+新内容HTTP 1.0 Expire: 用户PC时间点A
Last-Modified: 服务器文件修改时间点B请求头:If-Modified-Since: 服务器文件修改时间点B
响应: 304+空/200+新内容HTTP 1.0的Expire是用户PC时间,有可能是错的,Last-Modified是服务器文件修改时间点,精确到秒,所以如果1s之内文件被修改N次,服务器是识别不出来变化的服务器禁用缓存
不加
Cache-Control,浏览器也出缓存静态资源,比如GET请求,或者你的状态码为200, 203, 206, 300, 301, 400等
手动禁用缓存:Cache-Control: max-age=0, must-revalidate或者Cache-Control: no-cacheCache-Control: no-cache意思时不缓存可以协商,Cache-Control: no-store意思是不缓存不协商浏览器禁用缓存
请求地址上加随机数
请求头加Cache-Control: no-cache, no-store, max-age=0Pragma是什么它用来向后兼容只支持
HTTP/1.0协议的缓存服务器,那时候HTTP/1.1协议中的Cache-Control还没有出来
请求头为:Pragma: no-cache, 其行为与Cache-Control: no-cache一致
总结
优化工具
Network, Performance, Rendering, FPS, Coverage
DNS
Prefetch
TCP
连接复用,并行,管道,多路复用,服务端推送
HTTP
合并,内联,压缩,精简(Tree Shaking),Cookie Free, CDN, 缓存,内容协商
代码优化
CSS在先,JS在后,代码拆分,动态导入,懒加载,预加载,CSS优化,JS优化


