Kodokon kodokon.com

加载性能:defer、async、preload 与 prefetch

用 defer 和 async 安排脚本的执行顺序,再用 preload、preconnect 和 prefetch 引导网络。

10 分钟 · 3 题

在 Kodokon 中打开本课

一个经典的 <script src>阻塞 HTML 解析:浏览器停下、下载、执行,然后再继续。两个属性改变了局面。defer 与解析并行下载,并按文档顺序执行脚本,就在 DOMContentLoaded 之前:它是你应用代码的默认选择,因为这些代码可能依赖 DOM 和其他脚本。async 也并行下载,但一旦文件到达就执行,不保证顺序:把它留给像分析统计这样不依赖任何东西的独立脚本。

HTML
<script src="/js/analytics.js" async></script>
<script src="/js/vendor.js" defer></script>
<script src="/js/app.js" defer></script>
vendor.js 始终会在 app.js 之前运行

有些关键资源浏览器发现得非常晚:CSS 文件里引用的字体、由 JavaScript 加载的图片。<link rel="preload"> 通过直接在 <head> 中声明资源来修复这种迟到发现,并带上必需的 as 属性,好让浏览器应用正确的优先级和正确的缓存。教科书式的例子:Web 字体,否则它们要等到 CSS 下载并解析之后才会被请求。

HTML
<link rel="preload" as="font" type="font/woff2"
      href="/fonts/inter-var.woff2" crossorigin>
<link rel="preload" as="image"
      href="/img/hero-1600.jpg" fetchpriority="high">
提前发现一个字体和 LCP 图片

最后一族:低优先级的网络提示。<link rel="preconnect"> 会提前建立完整连接(DNS、TCP、TLS),指向一个你肯定会用到的第三方源:在第一次请求上最多可节省 300 ms。dns-prefetch 是它的轻量表亲(只做 DNS 解析),对于不太确定的源作为回退很有用。而 prefetch 会在空闲时间下载一个用于下一次导航的资源:比如从购物车前往的结账页。取舍很清晰:preload 服务当前页面,prefetch 押注下一个页面。

HTML
<link rel="preconnect"
      href="https://api.example.com">
<link rel="dns-prefetch"
      href="https://cdn.example.com">
<link rel="prefetch" href="/checkout.html">
提前建立连接,并押注下一次导航

知识检测

确认你已牢记本课的重点内容。

  1. defer 提供了哪个 async 没有的保证?
    • 与 HTML 解析并行下载
    • 按文档顺序执行,在 DOMContentLoaded 之前
    • 在页面的任何渲染之前执行
  2. 为什么同源字体的 preload 上需要 crossorigin?
    • 字体总是以 CORS 模式请求;没有它,文件会被下载两次
    • 这是 WOFF2 格式的安全要求
    • 没有它,preload 会被默认的 CSP 阻止
  3. rel="prefetch" 的正确用途是什么?
    • 加速当前页面上的一个关键资源
    • 以低优先级下载下一次导航可能用到的资源
    • 强制把一个文件永久缓存