跳转到内容

资源提示:rel="preload" 与 rel="preconnect"

发布于

一句话: <link rel="preload"> 与 <link rel="preconnect"> 都是在 <head> 中声明 的资源提示,但作用不同——preload 会提前获取一个具体的高优先级资源,而 preconnect 只是 预先为某个源建立连接(DNS、TCP,对 HTTPS 还包括 TLS),不获取任何内容。

根据 MDN,<link rel="preload"> 让你在页面很快就会需要某个资源时提前声明这次获取, 使浏览器在页面生命周期的早期——即浏览器主渲染流程启动之前——就开始加载它,从而降低 阻塞页面渲染的可能性。

<link rel="preload" href="/fonts/brand.woff2" as="font" type="font/woff2" crossorigin>

根据 MDN,as 属性标识资源类型,使浏览器能够应用正确的 Accept 请求头、正确应用内容 安全策略,并为页面的真实请求复用预加载的资源。

rel="preconnect":预热连接,不获取任何内容

Section titled “rel="preconnect":预热连接,不获取任何内容”
<link rel="preconnect" href="https://api.example.com">

根据 MDN,preconnect 通过预先执行部分或全部连接握手,为将来来自该源的跨源请求、导航 或子资源提供先机。它对同源请求没有帮助,因为该连接本已建立。由于向过多第三方源预连接会 适得其反,MDN 建议只将其保留给最关键的少数几个源,对不那么关键的源改用 dns-prefetch。

根据 MDN,crossorigin 属性必须匹配 preload 所代表的真实请求的 CORS 与凭据模式——同源 资源也可能需要它。根据 MDN,字体无论同源与否都以匿名模式 CORS 发出请求。

function preloadFont(href) {
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'font';
link.type = 'font/woff2';
link.crossOrigin = 'anonymous';
link.href = href;
document.head.appendChild(link);
}

根据 MDN,HTMLLinkElement.relList 是反映元素 rel 属性的一个实时 DOMTokenList, DOMTokenList.supports() 会报告某个 token 是否受支持——用它在依赖任一提示前先做特性检测:

function supportsResourceHint(rel) {
const link = document.createElement('link');
// 不仅要判断 relList 是否存在,还要判断 supports 本身是否是函数:
// 调用一个不存在的方法会抛出异常,而不是返回 false,这会让检测失效。
return 'relList' in link && typeof link.relList.supports === 'function' && link.relList.supports(rel);
}
if (supportsResourceHint('preload')) {
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'font';
link.type = 'font/woff2';
link.crossOrigin = 'anonymous';
link.href = '/fonts/brand.woff2';
document.head.appendChild(link);
} else {
// preload 不受支持(或没有 relList.supports):无需额外回退——
// 浏览器仍会在真正的 @font-face 请求触发时发现并获取该字体,
// 只是少了这个提示原本能带来的提前起步。
}
if (supportsResourceHint('preconnect')) {
const link = document.createElement('link');
link.rel = 'preconnect';
link.href = 'https://api.example.com';
document.head.appendChild(link);
} else {
// preconnect 不受支持:无需回退,浏览器在发出真实的跨源请求时
// 仍会正常建立连接。
}

根据 MDN,rel="preload" 与 rel="preconnect" 均已 Baseline 广泛可用——preload 自 2021 年 1 月起,preconnect 自 2020 年 1 月起——意味着在 Baseline 浏览器中已保持两年多的 一致支持。

  • 为每个 preload 链接设置 as,使其与资源的真实请求类型匹配(font、style、 script、image 等)。
  • 只要真实请求会以 CORS 模式发出就添加 crossorigin——字体请求始终需要,即使同源 也不例外——以便与真实请求匹配。
  • 根据 MDN,将 preconnect 保留给最关键的连接;其余第三方源改用 dns-prefetch。
  • 只 preload 当前页面真正尽早需要的资源——根据 MDN,预加载未被使用的替代格式可能 浪费带宽。