预解析、预连接、预加载

做前端性能优化时,经常会配置DNS预解析、预连接、资源预加载的标签,这些标签是如何起作用的,有哪些参数可以配置,本文做一个记录总结。

DNS预解析

基本语法:

1
<link rel="dns-prefetch" href="//example.com">

DNS解析过程:

  1. 用户输入域名 → 浏览器检查本地DNS缓存
  2. 缓存未命中 → 向本地DNS服务器查询
  3. 递归查询 → 本地DNS服务器向根DNS服务器查询
  4. 返回IP地址 → 建立TCP连接

DNS预解析的作用:

  • 在页面加载时并行进行DNS解析
  • 当真正需要连接时,IP地址已经解析完成
  • 减少DNS解析延迟(通常100-200ms)

预连接

基本语法:

1
2
<link rel="preconnect" href="https://api.example.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>

预连接包含三个步骤:

  1. DNS解析:解析域名到IP地址
  2. TCP连接:建立TCP三次握手
  3. TLS协商:如果是HTTPS,进行TLS握手

预连接的作用:

  • 提前建立完整的网络连接
  • 减少连接建立时间(通常300-500ms)
  • 特别适合HTTPS连接

合理使用策略

DNS预解析和预连接的合理使用策略:

1
2
3
4
5
6
7
8
9
10
11
<!-- 1. 关键资源使用preconnect -->
<link rel="preconnect" href="https://cdn.example.com">

<!-- 2. 一般资源使用dns-prefetch -->
<link rel="dns-prefetch" href="//analytics.example.com">

<!-- 3. 跨域资源添加crossorigin -->
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>

<!-- 4. 避免过度优化 -->
<!-- 不要为所有域名都添加preconnect -->

DNS预解析和预连接的核心原理:

  • DNS预解析:提前解析域名,减少DNS查询时间
  • 预连接:提前建立完整连接,减少连接建立时间
  • 浏览器优化:利用空闲时间进行网络准备
  • 用户体验:减少页面加载时的网络延迟

使用建议:

  • 为关键资源使用preconnect
  • 为一般资源使用dns-prefetch
  • 避免过度优化,合理使用
  • 监控实际效果,持续优化

这些技术通过提前进行网络准备,显著提升了网页的加载性能。

疑问:直接优化当前页面加载 or 优化外部资源加载

DNS预解析和预连接主要优化:

  • 当前页面中的外部资源加载速度
  • 页面加载过程中的后续请求速度
  • 不是直接优化当前页面的初始加载
  • 例外:在单页应用(SPA)中,DNS预解析和预连接可以优化页面切换速度

详细分析各种场景:

传统多页应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 页面A -->
<!DOCTYPE html>
<html>
<head>
<!-- 这些优化对当前页面A的加载没有直接帮助 -->
<link rel="dns-prefetch" href="//cdn.example.com">
<link rel="preconnect" href="https://api.example.com">
</head>
<body>
<!-- 页面A的内容 -->
<img src="https://cdn.example.com/image.jpg"> <!-- 这个会受益 -->
<script src="https://api.example.com/data.js"></script> <!-- 这个会受益 -->
</body>
</html>

单页应用(SPA)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 用户从首页切换到用户页面
// 1. 首页加载时预连接API
// 2. 切换到用户页面时,API请求立即使用已建立的连接
// 3. 用户页面加载更快

// 首页组件
const Home = () => {
useEffect(() => {
// 预连接用户页面需要的API
preconnect('https://api.example.com');
}, []);

return <div>首页内容</div>;
};

// 用户页面组件
const UserList = () => {
useEffect(() => {
// 由于之前预连接了,这个请求会更快
fetch('https://api.example.com/users')
.then(res => res.json())
.then(data => setUsers(data));
}, []);

return <div>用户列表</div>;
};

时间线分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 页面加载时间线
const pageLoadTimeline = {
// 阶段1:页面初始加载(不受预连接影响)
initialLoad: {
dns: 0, // 当前页面域名已在地址栏
tcp: 0, // 当前页面连接已建立
html: 150, // HTML下载和解析
total: 150
},

// 阶段2:页面资源加载(受预连接影响)
resourceLoad: {
dns: 100, // 外部资源DNS解析
tcp: 200, // 外部资源TCP连接
tls: 150, // HTTPS TLS握手
download: 200, // 资源下载
total: 650
}
};

// 使用预连接后
const optimizedTimeline = {
initialLoad: {
dns: 0,
tcp: 0,
html: 150,
total: 150
},

resourceLoad: {
dns: 0, // 已预解析
tcp: 0, // 已预连接
tls: 0, // 已预连接
download: 200, // 只需下载
total: 200
}
};

总结

  • DNS预解析和预连接主要优化外部资源加载,不是直接优化当前页面的初始加载
  • 在单页应用(SPA)中,DNS预解析和预连接可以优化页面切换速度
  • 间接提升了整体用户体验
  • 减少了页面加载过程中的网络延迟
  • DNS预解析和预连接优化的是页面加载过程中的资源请求速度,而不是页面本身的初始加载速度

资源预加载

基本概念

预加载是浏览器在页面加载时主动下载未来可能需要的资源,而不是等到真正需要时才下载。

基本语法

1
2
3
4
5
6
7
8
9
<!-- 预加载关键资源 -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="main.js" as="script">
<link rel="preload" href="hero-image.jpg" as="image">
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

<!-- 预获取可能需要的资源 -->
<link rel="prefetch" href="next-page.html">
<link rel="prefetch" href="user-profile.js">

rel=”prefetch” vs rel=”preload”

特性 preload prefetch
优先级
用途 当前页面关键资源 未来页面可能资源
时机 立即加载 空闲时加载
带宽 抢占带宽 不抢占带宽

总结

预加载的核心原理:

  • 浏览器主动下载未来需要的资源
  • 利用网络空闲时间提前准备
  • 减少用户等待时间

关键要点:

  • preload:高优先级,立即加载
  • prefetch:低优先级,空闲时加载
  • 合理使用,避免过度预加载

预加载是现代Web性能优化的重要技术,通过提前准备资源显著提升用户体验。