资源预加载与预连接策略详解

HTMLPAGE 团队
14分钟 分钟阅读

全面讲解 Web 资源的预加载技术,包括 preload、prefetch、preconnect、dns-prefetch 等策略的使用场景和最佳实践。

#性能优化 #preload #prefetch #资源加载 #预连接

资源预加载概述

预加载技术允许开发者提前告知浏览器将要使用的资源,使浏览器能够更早地开始下载,减少用户等待时间。

类型用途优先级
preload当前页面关键资源
prefetch未来导航的资源
preconnect提前建立连接-
dns-prefetch提前解析 DNS-

preload - 预加载关键资源

基本用法

<!-- 预加载关键字体 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

<!-- 预加载关键脚本 -->
<link rel="preload" href="/js/critical.js" as="script">

<!-- 预加载首屏图片 -->
<link rel="preload" href="/images/hero.webp" as="image">

<!-- 预加载关键 CSS -->
<link rel="preload" href="/css/critical.css" as="style">

关键说明: as 属性必须指定正确的资源类型,否则浏览器可能不会正确使用该资源,导致重复下载。

动态预加载

function preloadResource(href: string, as: string) {
  const link = document.createElement('link')
  link.rel = 'preload'
  link.href = href
  link.as = as
  if (as === 'font') {
    link.crossOrigin = 'anonymous'
  }
  document.head.appendChild(link)
}

// 根据用户行为预加载
button.addEventListener('mouseenter', () => {
  preloadResource('/js/heavy-feature.js', 'script')
})

prefetch - 预取未来资源

页面级预取

<!-- 预取下一页 HTML -->
<link rel="prefetch" href="/about">

<!-- 预取下一页的资源 -->
<link rel="prefetch" href="/js/about-page.js" as="script">

智能预取策略

// 基于链接可见性预取
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const link = entry.target as HTMLAnchorElement
      prefetchPage(link.href)
      observer.unobserve(link)
    }
  })
})

document.querySelectorAll('a[href^="/"]').forEach(link => {
  observer.observe(link)
})

function prefetchPage(href: string) {
  const link = document.createElement('link')
  link.rel = 'prefetch'
  link.href = href
  document.head.appendChild(link)
}

preconnect - 预连接

提前建立 TCP 连接、TLS 握手,减少请求延迟:

<!-- 预连接到关键第三方源 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<link rel="preconnect" href="https://api.example.com">

使用场景

  • 第三方字体服务
  • CDN 域名
  • API 服务器
  • 统计分析服务

dns-prefetch - DNS 预解析

比 preconnect 更轻量,只做 DNS 解析:

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

preconnect vs dns-prefetch

<!-- 对于确定会用到的资源,两者结合使用 -->
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="dns-prefetch" href="//fonts.gstatic.com">
对比项preconnectdns-prefetch
DNS 解析
TCP 连接
TLS 握手
浏览器支持现代浏览器广泛支持

在现代框架中使用

Nuxt 3 配置

// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      link: [
        { rel: 'preconnect', href: 'https://fonts.googleapis.com' },
        { rel: 'preload', href: '/fonts/main.woff2', as: 'font', type: 'font/woff2', crossorigin: 'anonymous' }
      ]
    }
  }
})

动态 Head 管理

// 在页面组件中
useHead({
  link: [
    { rel: 'preload', href: product.value.image, as: 'image' }
  ]
})

最佳实践

  1. 不要过度预加载:只预加载确定会用到的关键资源
  2. 正确设置 as 属性:确保资源类型匹配
  3. 字体需要 crossorigin:即使同源也需要设置
  4. 监控效果:使用 DevTools 验证预加载是否生效
  5. 结合用户行为:基于鼠标悬停等行为智能预取

调试技巧

在 Chrome DevTools Network 面板中:

  • preload 资源显示 Priority: High
  • prefetch 资源显示 Priority: Lowest
  • 检查是否有"unused preload"警告

正确使用预加载策略可以显著改善页面加载速度和用户体验。