prefetch请求未发出的主因是未满足onload完成、浏览器空闲、页面未卸载三条件;其次为as属性错误、跨域或路径不合法、节省流量模式开启、Cache-Control禁止缓存等。

prefetch 请求根本没发出?先看 onload 和空闲条件
写了 <link rel="prefetch" href="/next.js" as="script"> 却在 Network 面板里看不到请求,大概率不是代码错了,而是浏览器压根没启动它。prefetch 不是“写完就发”,它必须等 window.onload 触发、主线程空闲、网络无高优任务(比如 preload 或同步脚本)时才尝试发起。
常见卡点包括:
- 页面里有长任务阻塞主线程,
onload拖延几十甚至几百毫秒 - 用户开了“节省流量”模式(Chrome/Edge 默认跳过 prefetch)
- 页面还没完全加载完就刷新或跳转,浏览器主动取消 prefetch
- 目标资源返回了
Cache-Control: no-store,浏览器连缓存都不建,直接不发请求
验证方式:打开 Chrome DevTools → Network 面板 → 右上角过滤器输入 prefetch(默认隐藏),别只盯着 XHR 或 JS 标签页。
as 属性写错等于白写,且完全静默失效
as 不是可选装饰,它直接决定浏览器怎么解析这个 prefetch 请求:走哪条缓存路径、加什么 Accept 头、是否触发 CORS。写错或漏掉,请求大概率降级为普通 fetch,甚至被忽略——而且不报错、不警告。
立即学习“前端免费学习笔记(深入)”;
必须严格匹配类型:
- 预取 JS 文件 →
as="script"(不能是as="js"或as="fetch") - 预取 HTML 页面 →
as="document"(Safari 对此支持弱,iOS 16.4 前基本无效) - 预取 CSS →
as="style"(不是as="css") - 预取字体 →
as="font"(注意:prefetch 不触发 CORS 预检,跨域字体静默失败)
乱填值如 as="json" 或 as="image",浏览器直接忽略该 <link>,Network 里完全没痕迹。
同源和路径写法是硬门槛,动态插入基本无效
prefetch 只在 HTML 解析阶段被识别,且目标 URL 必须与当前页同源(协议、域名、端口全一致)。跨域 prefetch 在 Firefox/Safari 中基本被无视,Chrome 虽支持但需服务端配合 CORS,实际很少生效。
路径也必须合规:
- ✅ 绝对路径:
href="/js/detail.js" - ✅ 根相对路径:
href="/assets/main.css" - ❌ 相对路径:
href="./main.css"(子目录下解析失败) - ❌ 协议相对:
href="//cdn.example.com/xxx.js"(非同源,且解析可能出错)
用 JS 动态创建并 append 的 <link>,99% 情况下被忽略——HTML 解析期已过,浏览器不认。构建工具(如 Webpack)自动生成的 prefetch,若未配置 publicPath 或 base,容易产出错误路径。
和 preload 同时存在会发两次请求,缓存也不共享
同一个 URL 如果既被 preload 又被 prefetch 声明,Chrome 会发两次独立请求:一次 Highest 优先级进当前页专用缓存分区,一次 Low 优先级进常规 HTTP 缓存。两者隔离,互不复用。
后果很实在:
- Network 面板能看到两个条目,
Initiator分别是preload和prefetch - 浪费带宽,尤其在慢网下
- 预取的资源如果没配
Cache-Control: public, max-age=31536000,下次跳转仍要重下,白忙一场
真正该用 preload 的只有首屏马上要用的资源(如关键字体、内联样式引用的图片);prefetch 只用于确定后续导航会用到的资源(如分页第二页的 JS chunk),且两者绝不混用同一 URL。
最容易被忽略的是:prefetch 的“低优先级”不是指它不重要,而是它根本不参与当前页面的调度队列——它只在 onload 后空闲时才动,所以哪怕你写了十个 prefetch,也不会拖慢首屏一毫秒;但一旦写错 as 或路径,它就连动都不会动。



















