Skip to content

资源加载与优先级

preload、prefetch、modulepreload 区别与 Priority Hints

一、资源加载优先级概览

1.1 浏览器默认优先级

资源类型默认优先级说明
HTMLHighest文档本身
CSS(阻塞渲染)High首屏样式
字体High避免 FOUT
同步 JSHigh阻塞解析
图片(视口内)HighLCP 相关
预加载资源Highpreload
异步/延迟 JSMedium不阻塞
图片(视口外)Low懒加载
prefetchLowest空闲时加载

1.2 加载流程

HTML 解析 → 发现资源 → 加入队列 → 按优先级调度 → 发起请求

                ├── preload  → 立即高优先级
                ├── 同步 script → 阻塞,高优先级
                ├── CSS → 高优先级
                ├── 图片 → 视口内高,视口外低
                └── prefetch → 空闲时低优先级

二、preload 预加载

2.1 语法与用途

html
<!-- 预加载关键资源,立即高优先级请求 -->
<link rel="preload" href="/critical.css" as="style">
<link rel="preload" href="/main.js" as="script">
<link rel="preload" href="/font.woff2" as="font" crossorigin>
<link rel="preload" href="/hero.webp" as="image">

2.2 as 属性

as 值用途
scriptJS 文件
styleCSS 文件
font字体文件(需 crossorigin)
image图片
fetchfetch/XHR 请求
documentiframe 文档

2.3 使用场景

  • 关键 CSS:首屏渲染必需的样式
  • 关键字体:避免文字闪烁 (FOUT)
  • LCP 图片:首屏大图提前加载
  • 关键 JS:首屏交互必需

2.4 注意事项

html
<!-- ❌ 错误:preload 后未使用,浪费带宽 -->
<link rel="preload" href="/unused.js" as="script">

<!-- ✅ 正确:preload 的字体需 crossorigin -->
<link rel="preload" href="/font.woff2" as="font" crossorigin>

<!-- ✅ 与 media 配合,按需加载 -->
<link rel="preload" href="/large.css" as="style" media="(min-width: 768px)">

三、prefetch 预获取

3.1 语法与用途

html
<!-- 低优先级,浏览器空闲时加载,用于下一页/后续可能用到的资源 -->
<link rel="prefetch" href="/next-page.js">
<link rel="prefetch" href="/next-page.css">

3.2 与 preload 的区别

对比项preloadprefetch
优先级高,立即加载低,空闲时加载
用途当前页关键资源下一页/后续可能用到的资源
缓存用于当前页存入 HTTP 缓存,下次用
时机发现即请求主资源加载完后

3.3 使用场景

  • 分页场景:预加载下一页的 JS/CSS
  • 路由预加载:SPA 预加载可能访问的路由 chunk
  • 图片预加载:用户 hover 时 prefetch 大图
javascript
// 路由预加载示例
router.beforeEach((to, from, next) => {
  if (to.name === 'Detail') {
    const link = document.createElement('link');
    link.rel = 'prefetch';
    link.href = '/chunks/detail.js';
    document.head.appendChild(link);
  }
  next();
});

四、modulepreload 模块预加载

4.1 语法与用途

html
<!-- 预加载 ES Module,比 preload as="script" 更高效 -->
<link rel="modulepreload" href="/module-a.js">
<link rel="modulepreload" href="/module-b.js">

4.2 与 preload 的区别

  • modulepreload:专为 ES Module 设计,会递归预加载 import 的依赖
  • preload as="script":只加载单个文件,不处理依赖
html
<!-- 主模块依赖 a.js、b.js,modulepreload 会一并预加载 -->
<link rel="modulepreload" href="/main.js">
<script type="module" src="/main.js"></script>

4.3 使用场景

  • 使用 ES Module 的 SPA
  • 需要提前加载模块依赖树

五、fetchpriority 优先级提示

5.1 语法(Chrome 101+)

html
<!-- 提升 LCP 图片优先级 -->
<img src="/hero.jpg" fetchpriority="high" alt="Hero">

<!-- 降低非关键图片优先级 -->
<img src="/decoration.png" fetchpriority="low" alt="Decoration">

<!-- 预加载时指定优先级 -->
<link rel="preload" href="/font.woff2" as="font" crossorigin fetchpriority="high">

5.2 取值

说明
high提升优先级
low降低优先级
auto默认,浏览器自动决定

5.3 使用场景

  • LCP 图片fetchpriority="high" 确保首屏大图优先
  • 首屏以下图片fetchpriority="low" 避免抢占带宽
  • 懒加载占位图fetchpriority="low" 或省略

六、dns-prefetch 与 preconnect

6.1 dns-prefetch

html
<!-- 提前解析 DNS,减少后续请求延迟 -->
<link rel="dns-prefetch" href="https://cdn.example.com">
<link rel="dns-prefetch" href="https://api.example.com">

6.2 preconnect

html
<!-- 提前建立 TCP + TLS 连接(含 DNS) -->
<link rel="preconnect" href="https://cdn.example.com" crossorigin>

6.3 对比

方式DNSTCPTLS
dns-prefetch
preconnect
  • 关键第三方域名用 preconnect
  • 非关键第三方用 dns-prefetch(更省资源)

七、懒加载策略

7.1 原生 loading="lazy"

html
<!-- 视口外图片延迟加载 -->
<img src="/image.jpg" loading="lazy" alt="...">

<!-- iframe 懒加载 -->
<iframe src="/embed" loading="lazy"></iframe>

7.2 IntersectionObserver 懒加载

javascript
const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src || img.src;
      observer.unobserve(img);
    }
  });
});
document.querySelectorAll('img[data-src]').forEach((img) => observer.observe(img));

7.3 动态 import 懒加载

javascript
// 路由级懒加载
const Detail = () => import('./Detail.vue');

// 组件内懒加载
const HeavyChart = defineAsyncComponent(() => import('./HeavyChart.vue'));

八、资源加载决策流程

发现资源

    ├── 有 preload? ──Yes──▶ 高优先级立即请求

    ├── 有 prefetch? ──Yes──▶ 低优先级,空闲时请求

    ├── 有 modulepreload? ──Yes──▶ 预加载模块及依赖

    ├── 有 fetchpriority? ──Yes──▶ 调整优先级

    └── 默认 ──▶ 按资源类型分配优先级

九、高频面试题

Q1: preload 和 prefetch 的区别?

答案:preload 高优先级、立即加载,用于当前页关键资源;prefetch 低优先级、空闲时加载,用于下一页或后续可能用到的资源。

Q2: modulepreload 和 preload 的区别?

答案:modulepreload 专为 ES Module 设计,会递归预加载 import 的依赖;preload 只加载单个文件。

Q3: 如何优化 LCP?

答案:对 LCP 图片使用 fetchpriority="high"rel="preload" as="image";对关键字体使用 rel="preload" as="font" crossorigin;对关键第三方域名使用 rel="preconnect"

Q4: dns-prefetch 和 preconnect 的区别?

答案:dns-prefetch 只解析 DNS;preconnect 完成 DNS + TCP + TLS 全流程,适合关键第三方。

前端面试知识库