# 从输入url开始能做哪些优化

# DNS 查询优化

当然针对 DNS 的优化就是减少 DNS 解析的时间,由于浏览器缓存机制的存在,我们只需要对首次访问进行优化(虽然我们现在只是请求了一个html文件,但是html文件里还会有我们后续要请求的 css/js/img 等),即适当减少要解析的域名个数,考虑到其他优化机制可以将页面及页面内资源发布到 2-4 个域名上。

# TCP 连接优化

我们要对 TCP 和 SSL/TLS 握手耗时进行优化。有以下几个因素:

  • 数据往返延迟:主要受地理位置影响,使用较近的服务器进行数据传输会减少数据往返的时间,我们可以通过在不同的地区部署服务器(如: CDN,其也会用到 DNS 解析,可能在 DNS 解析阶段就完成了对客户端访问域名到距离最近的服务器的映射),将数据放到接近客户端的地方,可以减少网络往返时间。

  • 证书链:其实数据往返延迟优化不只是针对 TCP 握手阶段的,后续基于 TCP 的数据传输都会收益,如 SSL/TLS 握手和后续的请求响应。那么证书链是影响 SSL/TLS 握手的一个重要因素,证书链是服务器向客户端发送的证书内的信息,由站点证书、中间证书颁发机构的证书、根证书组成(比较类似 DNS 域名解析服务器之间的关系)。

原因

  1. TCP 慢启动:由于 TCP 慢启动(为避免拥塞,TCP 连接初始只能发送较少的分组,然后等待客户端确认,然后翻倍,经过几次往返直至到达阈值)和 TLS/SSL 握手数据发送一般位于TCP连接慢启动阶段的关系,证书数据过多会超过 TCP 连接的初始值,会造成数据往返次数的成倍增加。

  2. 证书链验证过长:由于客户端浏览器在验证证书可靠性时,会递归验证链条中的每个节点至根证书,也会增加握手时间。

方法

  1. 减少中间证书颁发机构的数量,优化至只有站点证书和一个中间证书颁发机构。

  2. 不要添加根证书信息,浏览器内置信任名单中有根证书。

握手次数:前两点优化都是针对的握手时间的优化,握手次数也是影响延迟的重要因素。我们在后面谈到大量请求的时候再说这一点。

初始拥塞窗口:适当增大初始拥塞窗口大小,即增大 TCP 连接初始可发送的分组大小。

# 获得页面后响应优化

避免重定向:如果服务器返回了跳转重定向(非缓存重定向),那么浏览器端就会向新的 URL 地址重新走一遍 DNS 解析和建立连接。所以应该避免不必要的重定向。

# 解析渲染页面优化

浏览器目前使用的 HTTP 协议版本大多是 1.1 和 2,二者有些不同,但是底层都是使用 TCP 进行数据传输。由于 TCP 握手耗时,和 SSL/TLS 更加耗时,我们需要减少整个加载过程中需要建立的连接的次数和耗时。

复用:针对 HTTP1.1 的最好方法是启用长连接:HTTP 1.1 提供了默认开启长连接功能,相对于短连接(每请求一个资源建立然后断开一次TCP连接),同一客户端 socket(浏览器可能会开多个端口并行请求)针对同一 socket(域名+端口)后续请求都会复用一个 TCP 连接进行传输,直到关闭这个 TCP 连接。

加速:针对 SSL/TLS 握手有会话恢复机制,验证通过后,可以直接使用之前的对话密钥,减少握手往返。

# 加载优化

# 加载前

  • 增加带宽:但是大部分情况下服务器带宽并不是影响延迟的主要因素。

  • 智能 DNS 解析:根据客户端的 IP 地址,将域名解析为最近的或不跨运营商的服务器的 IP 地址,解决地理位置和跨运营商的延迟问题。

  • CDN:使用某种分析方式根据节点服务器的地理位置、负载情况、资源匹配情况从遍布各地的节点服务器中找出最合适的静态资源服务器。

  • 负载均衡:使用 DNS 负载均衡、IP 负载均衡、反向代理负载均衡等方式从一堆服务器(集群相同职责)或一组服务器(分布式职责区分)中选择最合适的服务器处理请求。

  • 这几种技术可能是相互结合的,比如 CDN 会用到 DNS 智能解析和负载均衡等。

  • 其中使用了跳转重定向方式的会重新进行 DNS 解析和握手,其中一部分优化实际是在域名的DNS解析部分完成的。

# 开始加载

HTTP 1.1

  • 减少页面中需要发起的请求总数,如我们常规使用的代码合并,雪碧图(精灵图/Sprite 合并小图标),将图片转为 base64 写入其他文件,避免空的img src属性等。

  • 切割拆分数据,让首屏数据优先加载等。

  • 增加:增加资源的分布域名,部署在不同域名下,“突破”浏览器并行连接限制(结合 DNS 部分,不易过于分散,且过多连接会共享带宽,且移动端的解析更加缓慢)。

HTTP 2

  • Gzip:启用 Gzip 可对响应体进行压缩,可减少70%大小的数据体积。

  • 减少cookie:去除不必要的 cookie,设置合适过期时间。

  • 舍弃cookie:对于静态文件请求我们可以不要 cookie,即 HTTP1.1中提到的,分布在其他域名下,子域名设置合理的 domian(cookie 作用域)。

  • 首部压缩:HTTP2 还提供了首部压缩功能,即通过双方共有的一些字典,将首部信息(状态行、请求/响应头)“映射”为更简短的数据。

  • 图片:使用合适的图片大小和图片格式,可以节省大小。

  • 合理利用缓存

# 页面解析渲染优化

# 问题

资源下载:

  • css下载时会阻塞渲染(带有 media 属性除外)。

  • 遇到 script 标签时,DOM 构建停止,此时控制权移交至 js,直到脚本(下载)执行完毕,此时浏览器有优化一般会下载其他资源,但是不会解析。如果js中有对 CSSOM 的操作,还会先确保 CSSOM 已经被下载并构建。

  • 图片资源下载不会产生阻塞。

重绘重排导致重新进行渲染树的生成:

  • 重排(回流):会重新计算布局,通常由元素的结构、增删、位置、尺寸变化引起,如:img下载成功后,替换填充页面img元素,引起尺寸变化;也会由 js 的属性值读取引起,如读取 offset、scroll、cilent、getComputedStyle 等信息。

  • 重绘:简单外观的改变会引起重绘,如颜色变化等。

  • 重排一定重绘。

# 优化

dom

  • 简化 dom 结构,减少 DOM 树和渲染树构建成本,减少页面元素个数,如使用列表表格数据分页,简单表格不要使用复杂第三方组件等方式。

js

  • 将js脚本标签放在页面 body 底部,减少对其他过程的阻塞。

  • 延迟执行:对不修改页面的外链 script 使用 defer 属性,使脚本并行下载不阻塞,下载后不立刻执行,而在所有元素解析之后执行。

  • 减少和合并不必要的 dom 相关操作,如使用 DocumentFragment、修改classname 而不是各项 style 等,减少对重绘和重排的触发。

css

  • 将 css 放入 head 中,提前加载,并防止html渲染后重新结合css引起页面闪烁。

  • 减少 css 层级和 css 选择器复杂度,提高解析速度,虽然浏览器有优化。

  • 使用更高性能的 css 样式,如 flex 代替 float。

  • 开启复合层,如使用3d变换、opacity 等,使该元素及其子元素不导致外部的重排,但是也有坑。

  • 合理使用脱离文档流的样式,减少对外部重排的影响,如 absolute。

文件数量

  • 减少首次下载的文件数量大小,使用图片懒加载,js 的按需加载等方式,也可以节省用户流量,甚至使用 storage 存储进行 js、css 文件的缓存。

  • 拆分页面资源,首屏数据优先加载等。

# 其他优化措施

  • 使用 PWA,让用户在没有得到数据时也能看到页面。

  • 对页面某些 ajax 请求数据进行 storage 存储。

  • 加载进度、骨架图、占位图等类似让用户感觉好一点的措施。

  • 及时更新升级服务器,优化措施依赖于服务器支持。

  • 预渲染

  • 优化资源加载顺序

本文转载总结自:

从输入url开始能做哪些优化 (opens new window)