4. 网络层优化(上):HTTP/2 与 HTTP/3 协议优势、资源预加载(Preload/Prefetch)、DNS 预解析(dns-prefetch)
聊到 Vue 项目的性能优化,很多人第一反应是「代码层面怎么搞」。但说实话,我见过太多项目,代码写得挺漂亮,结果首屏加载慢得像蜗牛爬。问题出在哪?网络层。
你想想看,用户打开你的页面,第一步不是执行 JS,而是发 HTTP 请求。如果这层没优化好,后面再多的代码优化都是白搭。今天我们就来聊聊网络层的几个关键点:HTTP 协议选型、资源预加载、还有 DNS 预解析。
4.1 HTTP/2 与 HTTP/3:为什么它们比 HTTP/1.1 快?
我记得几年前接手一个老项目,首屏要加载 80 多个静态资源。HTTP/1.1 下,浏览器对同一域名最多开 6 个连接,剩下的资源只能排队等。那体验,简直了。
后来我们切到 HTTP/2,效果立竿见影。为什么?
HTTP/2 的核心优势
- 多路复用:一个 TCP 连接可以同时传输多个请求和响应。说白了,不用排队了。
- 头部压缩:HPACK 算法能把重复的头部信息压缩掉,减少传输量。
- 服务器推送:服务器可以主动把资源推给客户端,不用等客户端请求。
重要提示:HTTP/2 要求使用 HTTPS。如果你还在用 HTTP,先升级到 HTTPS 再说。
HTTP/3 又强在哪?
HTTP/3 基于 QUIC 协议,底层用的是 UDP 而不是 TCP。为什么这么做?因为 TCP 的「队头阻塞」问题在弱网环境下特别明显——一个包丢了,后面的都得等。QUIC 解决了这个问题。
我在项目中测试过,移动端弱网环境下,HTTP/3 的首字节时间比 HTTP/2 快了 30% 左右。当然,目前 CDN 和浏览器的支持还在普及中,但趋势已经很明显了。
| 特性 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 连接复用 | 有限(6个连接) | 多路复用 | 多路复用 |
| 队头阻塞 | 严重 | 存在(TCP层) | 无 |
| 头部压缩 | 无 | HPACK | QPACK |
| 传输协议 | TCP | TCP | QUIC (UDP) |
| 弱网表现 | 差 | 一般 | 优秀 |
我的建议:新项目直接上 HTTP/2,CDN 支持 HTTP/3 的话也开启。老项目升级 HTTP/2 基本是改个配置的事,收益却很大。
4.2 资源预加载:Preload 与 Prefetch
你有没有遇到过这种情况:页面已经渲染了,但某个关键图片或字体还在加载,导致布局抖动?这就是资源加载时机没把握好。
Preload 和 Prefetch 就是用来解决这个问题的。它们告诉浏览器:「嘿,这个资源很重要,提前帮我加载一下。」
Preload:当前页面必须的
Preload 用于加载当前页面马上要用到的资源。比如字体文件、首屏图片、关键 CSS 或 JS。
<!-- 预加载字体文件 -->
<link rel="preload" href="/fonts/iconfont.woff2" as="font" type="font/woff2" crossorigin>
<!-- 预加载首屏图片 -->
<link rel="preload" href="/images/hero-banner.webp" as="image">
<!-- 预加载关键 JS -->
<link rel="preload" href="/js/app.js" as="script">
注意 as 属性一定要写对。我见过有人把字体写成 as="script",结果浏览器不缓存,白加载了。
Prefetch:未来可能用到的
Prefetch 用于加载用户下一步可能访问的资源。比如下一个页面的 JS、图片等。
<!-- 预获取下一个页面的资源 -->
<link rel="prefetch" href="/next-page.js" as="script">
<link rel="prefetch" href="/next-page.css" as="style">
避坑指南:我曾经在一个项目中过度使用 Prefetch,把整个站点的资源都预加载了。结果用户只看了首页就走了,白白浪费了带宽。Preload 和 Prefetch 要用在刀刃上,别滥用。
在 Vue 项目中使用
在 Vue CLI 或 Vite 项目中,你可以通过配置来生成 Preload 和 Prefetch 标签。
Vue CLI 配置:
// vue.config.js
module.exports = {
chainWebpack: config => {
// 关闭默认的 preload 和 prefetch
config.plugins.delete('preload')
config.plugins.delete('prefetch')
// 手动添加需要的
config.plugin('preload').tap(args => {
args[0].rel = 'preload'
args[0].include = 'initial'
args[0].fileBlacklist = [/\.map$/, /hot-update\.js$/]
return args
})
}
}
Vite 配置:
// vite.config.js
export default {
build: {
rollupOptions: {
output: {
// Vite 默认会生成 preload 标签
// 可以通过 manualChunks 控制分块
}
}
}
}
小技巧:在 Vue 路由的懒加载场景中,可以用 Prefetch 预加载下一个路由的组件。用户点击导航时,资源已经准备好了,切换几乎无延迟。
4.3 DNS 预解析:dns-prefetch
DNS 解析需要时间。虽然通常只有几十毫秒,但在移动端或弱网环境下,这个时间可能被放大到几百毫秒。
dns-prefetch 就是让浏览器提前解析域名,等真正请求时直接拿 IP 地址。
<!-- 预解析第三方域名 -->
<link rel="dns-prefetch" href="//api.example.com">
<link rel="dns-prefetch" href="//cdn.example.com">
<link rel="dns-prefetch" href="//fonts.googleapis.com">
什么时候用?
- 页面中有第三方资源(CDN、API、字体库等)
- 用户即将跳转到其他域名
- 移动端网络环境较差时
和 Preconnect 的区别
Preconnect 比 dns-prefetch 更进一步,它除了解析 DNS,还会完成 TCP 握手和 TLS 协商。
<!-- preconnect 更强大,但开销也更大 -->
<link rel="preconnect" href="//api.example.com" crossorigin>
我个人习惯:对关键域名用 preconnect,对次要域名用 dns-prefetch。比如 API 域名用 preconnect,统计域名用 dns-prefetch。
重要提示:dns-prefetch 和 preconnect 不要滥用。每个域名都会占用浏览器的连接池,太多反而影响性能。一般建议控制在 3-5 个以内。
4.4 实战建议:把这些优化落地到 Vue 项目
好了,理论说完了。怎么落地?我给你一个 checklist:
- 检查你的服务器是否支持 HTTP/2:Nginx 开启 HTTP/2 只需加一行配置
listen 443 ssl http2; - 在 index.html 中添加 Preload:预加载首屏字体、关键图片
- 在路由配置中添加 Prefetch:预加载下一个页面的组件
- 在 head 中添加 dns-prefetch:预解析第三方域名
- 用 Chrome DevTools 验证:打开 Network 面板,看资源加载时序
我记得有一次帮一个电商项目做优化,只做了这三件事——切 HTTP/2、加 Preload、加 dns-prefetch——首屏加载时间从 4.2 秒降到了 2.1 秒。效果就是这么明显。
最后提醒一句:网络层优化是性价比最高的优化之一。改几行配置,加几个 link 标签,就能看到实实在在的效果。别等到用户抱怨了才想起来做。