rel="prefetch"不是并发调度机制,它仅在浏览器空闲时以Low优先级发起请求,同一域名通常限1–2个,且无进度监听、失败fallback或中断能力。

rel="prefetch"根本不是并发调度机制
它不控制并发数、不抢占带宽、不排队等待——浏览器只在空闲时以Low优先级发起请求,且同一域名下通常最多发1–2个。写十个<link rel="prefetch">,Chrome 可能只发出两个,Safari 可能一个都不发,Firefox 默认关闭(network.prefetch-next = false)。这不是 bug,是设计如此。
常见误判:看到 Network 面板里 prefetch 请求没全出现,就以为代码失效。实际是浏览器主动跳过,连pending状态都不会显示。
- 浏览器空闲 ≠ 网络空闲:后台有
fetch()、WebSocket 或长任务,prefetch 就被挂起 - 同域名并发极低,超量声明等于白写,还污染 HTTP 缓存
- 没有 API 可监听进度,失败也无法 fallback,更不能 abort 或 retry
高并发外部资源必须用 preconnect + dns-prefetch 组合
真正能缓解并发瓶颈的是preconnect和dns-prefetch,它们提前占位,不消耗连接池额度。但必须配对使用,且位置靠前、写法严格:
-
<link rel="dns-prefetch" href="//cdn.example.com">:只提取协议相对域名,//cdn.example.com/js/app.js会被整个忽略 -
<link rel="preconnect" href="https://cdn.example.com" crossorigin>:缺crossorigin,Safari 和旧 Chrome 不生效 - 两者都得放在
<meta charset>之后、<title>之前,否则解析器可能错过 -
//fonts.googleapis.com和//fonts.gstatic.com是两个独立域名,必须分别声明
注意:preconnect会建立 TCP+TLS 连接,但不发 HTTP 请求;dns-prefetch只查 DNS,不建连。二者都不增加并发上限,但能把原本串行的「DNS → TCP → TLS → HTTP」拆开并行推进。
立即学习“前端免费学习笔记(深入)”;
使用 Puppeteer + Chrome 将 HTML 渲染为中文 PDF,自动处理图表等待、Tab 展开、动画、测高、白边消除、防分页,适用于看板、报表、网页和交互图表转 PDF。
大型路由预取必须动态注入,不能静态堆砌
首页硬编码几十个prefetch链接,用户只访问首页却下载全部路由资源,移动端流量和缓存污染立刻飙升。可行做法是结合用户行为信号动态创建:
- 鼠标悬停导航菜单项时,
document.createElement('link')注入对应 chunk 的prefetch - 表单第一步输入完成(如邮箱校验通过),再预取
/step2.chunk.js - 用
IntersectionObserver监听导航区域进入视口,触发预取,避免过早加载
关键约束:href必须为绝对路径或根相对路径(如/js/routes/profile.abc.js),./js/在子路由下会解析失败;as值必须准确(as="script"不可省略),否则降级为as="document",流量翻倍。
preload 与 prefetch 混用时的优先级冲突风险
两者根本不在一个调度队列:preload是Highest优先级,立即抢占连接;prefetch是Low,等空闲。错把下一页资源写成preload,会直接挤掉critical.css或首屏图片,FCP 延迟 300ms+ 是常态。
-
preload只用于当前导航刚需:字体(as="font")、首屏 CSS(as="style")、动态 import 的模块(as="script") -
prefetch只用于用户大概率点击后才用的资源,体积建议 ≤ 100KB,且路径可预测(首页 → 列表页 → 详情页) - 别对整页 HTML 做
prefetch——浏览器只缓存 raw bytes,后续仍需完整导航流程 - 服务端渲染场景下,
prefetch对 JSON API 无效,浏览器不支持rel="prefetch"forfetch()
最容易被忽略的点:所有预取指令都依赖onload触发,而onload本身可能被长任务、404 图片或未 resolve 的 Promise 卡住——这时 prefetch 根本不会启动,连 Network 面板都看不到请求。


















