From 1250b1e30bf4db2154c2b5a2fa85c374bca42ee2 Mon Sep 17 00:00:00 2001 From: gaofuhong <157297759@qq.com> Date: Mon, 15 Jul 2024 16:18:25 +0800 Subject: [PATCH] feat: add performance optimization --- docs/.vuepress/src/sideBarData.js | 4 + .../1.\345\237\272\347\241\200.md" | 161 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 "docs/blog/frameSeries/performance/1.\345\237\272\347\241\200.md" diff --git a/docs/.vuepress/src/sideBarData.js b/docs/.vuepress/src/sideBarData.js index 09fc02c8..d9164e2f 100644 --- a/docs/.vuepress/src/sideBarData.js +++ b/docs/.vuepress/src/sideBarData.js @@ -66,6 +66,10 @@ const sideBarConfig = [ title: 'Nuxt', folder: 'Nuxt', }, + { + title: '性能优化', + folder: 'performance', + }, ] }, { diff --git "a/docs/blog/frameSeries/performance/1.\345\237\272\347\241\200.md" "b/docs/blog/frameSeries/performance/1.\345\237\272\347\241\200.md" new file mode 100644 index 00000000..c82575cd --- /dev/null +++ "b/docs/blog/frameSeries/performance/1.\345\237\272\347\241\200.md" @@ -0,0 +1,161 @@ +--- +title: 1.基础 +date: 2024-07-11 +sidebar: auto +tags: + - 性能优化 +categories: + - 性能优化 +--- + +## 1.Web性能介绍 +Web性能是客观的衡量标准,是用户对加载时间和运行时的直观体验。 +- 打开速度 +- 动画效果 +- 表单提交 +- 列表滚动 +- 页面切换 +... + + +## 2.优化方案 +- 从发出请求到收到响应的优化,比如DNS查询、HTTP长连接、HTTP2、HTTP压缩、HTTP缓存等 +- 关键渲染路径优化,比如是否存在不必要的重绘和回流 +- 加载过程的优化,比如延迟加载,是否有不需要在首屏展示的非关键信息,占用了页面加载的时间 +- 资源优化,比如图片、视屏等不同的格式类型会有不同的使用场景,在使用的过程中是否恰当 +- 构件优化,比如压缩合并、基于webpack构件优化方案等 +... + +## 使用Chrome DevTools测试性能 +**网络请求阻止** +- 打开方式:ctrl+shift+p -> show networl request blocking +- 启用网络请求阻止 +- 添加组织规则 + +**Coverage面板**
+通过Coverage面板监控并统计出网站应用运行过程中代码执行的覆盖率
+- 打开方式:ctrl+shift+p -> 搜索coverage(覆盖) -> 点击start instrumenting coverage and reload page +统计结果包括:文件的字节大小、执行过程中已覆盖的代码字节数,以及可视化的覆盖率条形图 + +**Memory面板(内存面板)** +- 打开方式:ctrl+shift+p -> memory(内存)-> 点击显示内存 + +**Performance面板(性能面板)** + +**FPS计数器**
+可在页面运行时提供对 FPS 的实时估计。 +- 打开方式:ctrl+shift+p -> FPS + +**Performance monitor**
+包括:CPU 占用率、JavaScript 内存使用大小、内存中挂的 DOM 节点数、JavaScript 事件监听次数及页面发生重绘与重排的处理时间等信息。 + +## 前端页面的生命周期 +问题:在浏览器地址栏输入一个网址到页面渲染出来,中间都经历了什么
+1. 输入地址(例如: https://www.example.com),浏览器解析URL(浏览器解析输入的URL,将其分为不同的部分,如协议(https)、域名(www.example.com)、路径(/)、查询参数等) +2. DNS解析(浏览器需要将域名转换为IP地址,这个过程称为DNS解析) +- 浏览器缓存:首先,浏览器会检查其缓存中是否有对应的IP地址 +- 操作系统缓存:如果浏览器缓存中没有,浏览器会查询操作系统缓存 +- 本地DNS服务器:如果操作系统缓存中也没有,操作系统会查询配置的本地DNS服务器(通常是ISP提供的) +- 递归查询:本地DNS服务器如果没有缓存,会进行递归查询,从根DNS 服务器开始,逐级查询顶级域名服务器、权威DNS服务器,直到找到对应的IP地址 +3. 建议TCP链接:TCP三次握手 +- SYN:浏览器发送一个 SYN 包到服务器,表示请求建立连接 +- SYN-ACK:服务器收到 SYN 包后,返回一个 SYN-ACK 包,表示同意连接 +- ACK:浏览器收到 SYN-ACK 包后,发送一个 ACK 包,表示连接建立成功 +4. SSL/TLS四次握手(只有https才有这一步) +5. 浏览器发送HTTP/HTTPS请求 +- 建立TCP连接后,浏览器发送HTTP或HTTPS请求到服务器。对于HTTPS,还包括建立TLS/SSL加密连接的步骤: +- ClientHello:客户端发送 ClientHello 消息,包含支持的加密算法等信息。 +- ServerHello:服务器响应 ServerHello 消息,选择加密算法,并发送服务器证书。 +- 证书验证:浏览器验证服务器证书的有效性。 +- 密钥交换:客户端和服务器协商对称密钥,用于后续加密通信。 +- 握手完成:双方确认加密参数,开始加密通信。 +6. 服务器响应请求并返回数据 +- 路由处理:根据请求路径,确定处理逻辑。 +- 数据库查询:如有需要,查询数据库获取数据。 +- 逻辑处理:根据业务逻辑生成响应内容。 +- 返回响应:服务器生成响应头和响应体,并发送回浏览器。 +7. 浏览器接受响应并解析 +- 解析HTTP响应头:获取状态码、内容类型、缓存控制等信息。 +- 解析HTML:将HTML文本解析为DOM树。 +- 解析CSS:将CSS文本解析为CSSOM树,并应用到DOM树中。 +- 解析JavaScript:解析并执行JavaScript代码,可能会操作DOM树和CSSOM树。 +- 解析图片、字体等资源:根据HTML和CSS内容,发送请求加载外部资源。 +8. 页面渲染 +浏览器将DOM树和CSSOM树结合起来,构建渲染树。渲染树包含了所有需要显示的节点及其样式信息 + +## DNS解析 +DNS解析是将人类容易记忆的域名(如www.example.com)转换为计算机可识别的IP(如192.0.2.1)地址。 + +DNS-prefetch(DNS预获取)是尝试在请求资源之前解析域名。这可能是后面要加载的文件,也可能是用户尝试打开的链接目标。域名解析和内容载入是串行的网络操作,所以这个方式能减少用户的等待时间,提升用户体验。 + +dns-prefetch 可帮助开发人员掩盖 DNS 解析延迟。 HTML的``元素通过dns-prefetch的rel属性值提供此功能 +```html + +``` +注意: +1. dns-prefetch仅对**跨域**域上的DNS查找有效,因此避免使用它来指向您的站点或域。这是因为,到浏览器看到提示时,您站点域背后的IP已经被解析 +2. dns-prefetch需慎用,多页面重复DNS预解析会增加重复DNS查询次数 +3. 默认情况下浏览器会对页面中和当前域名(正在浏览网页的域名)不在同一个域的域名进行预获取,并且缓存结果,这就是隐式的 DNS Prefetch。如果想对页面中没有出现的域进行预获取,那么就要使用显示 DNS Prefetch 了。 + +**更多DNS解析优化**
+1. 延长DNS缓存时间 +2. 尽可能使用A或AAAA记录代替CNAME +3. 使用CDN加速域名 +4. 自己搭建DNS服务 + +**清除DNS缓存**
+1. 清除浏览器DNS缓存 +- 清除DNS缓存:chrome://net-internals/#dns +- 有时候也需同时清除套接字缓存池:chrome://net-internals/#sockets + +2. 清除系统DNS缓存 +```js +// 在windows中查看DNS缓存记录 +ipconfig /displaydns + +// 在windows中清除DNS缓存记录 +ipconfig /flushdns + +// 在macOS中清除DNS缓存记录 +sudo killall -HUP mDNSResponder +``` + +## HTTP长连接 +### 短连接 +HTTP协议的初始版本中,每进行一次HTTP通信就要断开一次TCP连接。每次的请求都会造成无谓的TCP连接建立和断开,增加通信的开销。 + +为了解决这个问题,有些浏览器在请求时,用了一个非标准的Connection字段 +```HTTP +Connection: keep-alive +``` +这个字段要求服务器不要关闭TCP连接,以便其他请求复用。服务器同样回应这个字段。 +```HTTP +Connection: keep-alive +``` +一个可复用的TCP连接就建立了,直到客户端或服务器主动关闭连接。但是,这不是标准字段,不同实现的行为可能不一致,因此不是根本的解决办法。 + +### 长连接 +1997年1月,HTTP/1.1版本发布,只比1.0版本晚了半年。它进一步完善了HTTP协议,直到现在还是最流行的版本。
+HTTP 1.1 版的最大变化,就是引入了持久连接(HTTP Persistent Connections),即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive。
+持久连接的好处在于减少了TCP连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。另外,减少开销的那部分时间,使HTTP请求和响应能够更早的结束,这样Web页面的显示速度也就相应提高了。
+客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP连接。
+目前,对于同一个域名,大多浏览器允许同时建立6个持久连接。 + +## HTTP2 +HTTP/1.1版的头信息肯定是文本(SACII编码),数据体可以是文本,也可以是二进制。HTTP2/则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为“帧”:头信息帧和数据帧。
+HTTP/2是对HTTP/1.x的改进,旨在提高性能、减少延迟,并提供更高效的传输机制。 +1. 多工
+HTTP/2复用TCP连接,**在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应**,这样就避免了“队头堵塞”。
+举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。
+这样双向的、实时的通信,就叫做多工。
+2. 数据流
+因为HTTP/2的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。
+HTTP/2将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。
+数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。1.1版取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。
+客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。 +3. 头信息压缩
+HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和 User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。
+HTTP/2对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip 或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。 +4. 服务器推送
+HTTP/2允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。
+常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。