prefetch根本不会发请求的条件是未同时满足onload完成、主线程空闲、页面未卸载;其次为as属性错误、跨域或路径不合法、节省流量模式开启、Cache-Control:no-store等。

prefetch 什么时候根本不会发请求
写了 <link rel="prefetch"> 却在 Network 面板里看不到请求,大概率不是代码写错了,而是浏览器压根没启动它。它必须同时满足三个硬条件:页面已触发 window.onload、主线程空闲、网络无高优先级任务(比如 preload 或同步脚本)。常见卡点包括:
- 页面里有长任务阻塞主线程,
onload拖延几十毫秒以上 - 用户开了“节省流量”模式(Chrome/Edge 默认跳过
prefetch) - 目标 URL 跨域(协议/域名/端口任一不同),浏览器静默忽略,连 DNS 查询都不发
-
as属性缺失或写错(比如as="js"),请求被降级或直接丢弃 - 服务端返回
Cache-Control: no-store,浏览器连缓存都不建,不发请求
怎么写 href 和 as 才真正有效
href 必须是绝对路径或根相对路径(如 /assets/detail.chunk.js),不能用 ./detail.js 或 //cdn.example.com/detail.js —— 后者会被当成非法协议而静默失败。as 不是可选装饰,它决定缓存分区、请求头和是否复用。写错等于白写,且完全静默失效:
- 预取 JS 文件 → 必须写
as="script"(as="js"或as="fetch"无效) - 预取 CSS → 必须写
as="style"(不是as="css") - 预取 HTML → 可写
as="document",但 Safari 在 iOS 16.4 之前基本忽略,不推荐 - 字体别用
prefetch→as="font"不触发 CORS 预检,跨域字体大概率静默失败
静态写死 vs 动态注入,哪个更靠谱
直接在 <head> 里静态写 <link rel="prefetch" href="/assets/next.js" as="script"> 看似简单,但实际限制极多:必须同源、必须 onload 后空闲、Safari 兼容差、服务端带 nonce/token 的 HTML 缓存后可能执行失败。真正可控的做法是动态注入:
- 监听用户明确意图,比如卡片
mouseenter或滚动进入可视区 - 用
document.createElement('link')创建,显式设rel="prefetch"和as="script" - 加 200ms 延迟防误触,但别超 300ms,否则失去预取意义
- 只预取确定的构建产物路径(如 Vite 输出的
/assets/DetailPage.xxxx.js),不是路由路径/detail - React/Vue 中放在
useEffect或onMounted里执行,避免 SSR 渲染时报错
比 prefetch 更简单可靠的替代方案
如果你的“下一页”已经做了代码分割(比如 React 的 lazy(() => import('./DetailPage'))),直接调用 import('./DetailPage') 就行。浏览器会自动预取对应 chunk,本质是 runtime prefetch,优先级略高于 rel="prefetch",且所有现代浏览器都支持。它绕开了路径合法性、同源限制、onload 时机等全部坑,也不依赖服务端缓存策略。
立即学习“前端免费学习笔记(深入)”;
复杂点在于:prefetch 只存文件到 HTTP 缓存,不执行 JS、不恢复状态、不预渲染;用户点下一步,依然要 mount 组件、重新调 fetch()、校验表单——这些它一个都管不了。



















