一道面试题,开始性能优化之旅(3)-- DNS查询+TCP(一)

上图!

本篇开始我们来聊聊 DNS + TCP(TCP+ TLS),其实前端在这些个阶段能做的不多,但是 他们却与前端页面的性能的关系深远,如下图,

DNS

将域名解析为 IP 地址,这个目前没啥可说的,给服务器发送请求要找到服务器地址才行啊

TCP 连接(HTTP协议)

为什么需要TCP连接

我们一直说: HTTP协议是基于TCP协议的,而TCP协议是面向连接的,这是什么意思呢?

一、TCP/IP协议栈的分层本质

graph BT A[HTTP] -->|依赖| B[TCP] B -->|依赖| C[IP] C -->|依赖| D[物理链路]
  • HTTP :应用层协议,负责内容语义(如GET/POST)
  • TCP :传输层协议,解决可靠传输问题
  • IP :网络层协议,解决路由寻址问题

💡 核心矛盾 :IP协议是不可靠传输 (可能丢包/乱序),而HTTP需要完整有序的数据流


二、TCP如何解决三大致命问题?

1. 数据包乱序问题(IP层常态)

sequenceDiagram 客户端->>服务器: 发送包1 (seq=1) 客户端->>服务器: 发送包3 (seq=3,包2丢失) # 包2丢失 服务器->>客户端: ACK=1 (期待seq=2) 客户端->>服务器: 重发包2 (seq=2) 服务器->>客户端: ACK=3
  • TCP机制:序列号(seq)+确认号(ACK)+重传
  • HTTP受益 :浏览器收到的HTML文件顺序正确

2. 数据包丢失问题

flowchart LR A[发送数据] --> B{是否收到ACK?} B -->|超时未收到| C[重传数据] B -->|收到ACK| D[继续发送]
  • TCP机制:超时重传 + 快速重传
  • HTTP受益 :网页资源不会缺斤少两

3. 接收方过载问题

graph LR A[发送方] -->|高速发送| B[接收方] B -->|缓冲区满| C[发送rwnd=0] A -->|暂停发送| B
  • TCP机制:滑动窗口 + 流量控制
  • HTTP受益 :手机等小内存设备不会崩溃

三、TCP连接建立过程

三次握手全解析

sequenceDiagram 客户端->>服务器: SYN=1, seq=x 服务器->>客户端: SYN=1, ACK=1, seq=y, ack=x+1 客户端->>服务器: ACK=1, seq=x+1, ack=y+1
  • 第一步 :客户端证明自己的发送能力正常

    (SYN:声明自己的发送能力正常,试图验证对方的接收能力)

  • 第二步 :服务器证明自己的收发能力正常

    (SYN:对方声明自己的发送能力正常,试图验证对方的接收能力,ACK:声明自己的接收能力正常)

  • 第三步 :客户端证明自己的接收能力正常

    (ACK:声明自己的接收能力正常

🔐 连接本质 :通信双方建立状态共识

  • 客户端状态:ESTABLISHED
  • 服务器状态:ESTABLISHED
  • 双方约定:初始序列号(x/y)、窗口大小、MSS等

常见面试题:为什么需要三次握手

两次握手就像一个半截电话:你说完"喂",朋友答完"听到了",就完了。但朋友不知道你听到他没有,容易白等或出乱子。

也就是说两次握手无法验证客户端的接收能力,可能会让服务器一直傻等,浪费资源

建立连接耗时

注意:客户端发送完ACK后就认为连接已经建立完毕(而不是等待服务器端收到这个ACK)​,并开始传输应用层的数据(如HTTP报文)​。

服务器端收到这个ACK后才会开始把收到的数据交付给应用层(HTTP)​。

所以 其实 TCP建立连接的时间 是一个RTT

如何优化 TCP 建立连接耗时

理解TCP如何建立连接,以及背后的耗时。从本质上说,RTT之后,可以得到以下几个优化思路

减少物理距离

RTT从本质上来说就是网络传输的耗时,如果使机器与用户端的物理距离更短,就能相应地减少时间。后面CDN就是一种实践方法

preconnect

在已经知道页面中的图片需要建立连接的情况下,浏览器提供了preconnect的能力,允许提前建立好TCP连接,如下图所示。

1. 问题的背景

  • 默认情况下 ,浏览器会 串行加载资源 。例如:
    • 先下载并执行 JavaScript(阻塞后续操作)。
    • 等 JS 执行完成后,才开始建立图片资源的连接(DNS 查询、TCP 握手等)。
  • 这种串行行为会导致 不必要的等待时间,尤其是当后续资源(如图片)依赖独立域名时。

2. preconnect 的作用

preconnect 允许开发者 提前告知浏览器 :"稍后会用到某个域名的资源,请提前建立连接。"

这样,浏览器可以在 当前空闲时(如 JS 执行期间)提前完成:

  1. DNS 解析(将域名转换为 IP)。
  2. TCP 握手(建立网络连接)。
  3. TLS 协商(如果是 HTTPS 站点)。

当后续实际请求该域名的资源时,连接已经就绪,直接复用,节省了数百毫秒的延迟。

3. 如何使用

在 HTML 的 <head> 中添加 <link> 标签:

html 复制代码
<link rel="preconnect" href="https://example.com">
  • href:指定需要预连接的域名(协议需明确,如 https://)。
  • 浏览器会立即开始预连接,但不会下载资源。

4. 为什么 preconnect 包含 DNS 预解析?

  • 建立 TCP 连接前必须知道目标 IP,因此 preconnect 隐式包含了 DNS 预解析 (类似 dns-prefetch)。
  • preconnect 更彻底,不仅解析 DNS,还完成后续的 TCP/TLS 步骤。

5. 适用场景

  • 跨域资源:如 CDN 域名、第三方 API 等。
  • 关键路径资源:优先预连接影响首屏的域名。
  • 已知后续会使用的域名:避免串行等待。

6. 注意事项

  • 不要滥用:每个预连接会占用浏览器资源和服务器连接数,通常建议预连接 3-5 个最关键域名。

复用连接 和域名收拢

这两处优化会在后面详细说明,此处省略

总结

TCP连接耗时是一个非常典型的问题,在日常开发中几乎不会注意到TCP连接耗时,在本地用DevTools的Network面板或Performance面板往往也测试不到,因为本地在大多数情况下都是复用连接的

事实上,TCP连接耗时与很多因素有关,最终只能通过线上回收的数据来判断大多数用户在TCP连接上花费的真实耗时。它是一个通过本地测试很难进行复现,并且非常依赖数据分析手段才能解决的问题。

TCP 协议确实是以牺牲部分性能(连接建立时间)为代价的

相关推荐
局i7 小时前
v-for 与 v-if 的羁绊:Vue 中列表渲染与条件判断的爱恨情仇
前端·javascript·vue.js
suke7 小时前
紧急高危:Next.js 曝出 CVSS 10.0 级 RCE 漏洞,请立即修复!
前端·程序员·next.js
狮子座的男孩7 小时前
js函数高级:06、详解闭包(引入闭包、理解闭包、常见闭包、闭包作用、闭包生命周期、闭包应用、闭包缺点及解决方案)及相关面试题
前端·javascript·经验分享·闭包理解·常见闭包·闭包作用·闭包生命周期
深红8 小时前
玩转小程序AR-基础篇
前端·微信小程序·webvr
什么时候才能变强8 小时前
k6面试高频问题
面试·职场和发展·k6
风止何安啊8 小时前
从 “牵线木偶” 到 “独立个体”:JS 拷贝的爱恨情仇(浅拷贝 VS 深拷贝)
前端·javascript·面试
漫天黄叶远飞8 小时前
地址与地基:在 JavaScript 的堆栈迷宫里,重新理解“复制”的哲学
前端·javascript·面试
杨啸_新房客8 小时前
如何优雅的设置公司的NPM源
前端·npm
ohyeah8 小时前
深入理解 JavaScript 中的继承与 instanceof 原理
前端·javascript
linhuai8 小时前
flutter如何实现有登陆权限管理
前端