prefetch触发需满足onload完成、浏览器空闲、页面未卸载三条件,静态写死不可控;应改用intersectionobserver监听可视区+动态注入,仅预取确定路径资源并显式指定as="document"等类型。

prefetch 的触发时机根本不在用户点击前
它只在当前页 window.onload 完成、浏览器判定空闲(CPU/网络负载低)、页面未卸载时才发起请求——这意味着:用户点“加入购物车”按钮时,prefetch 还没开始,更别说完成。电商链路里常见的“列表页 → 商品详情页 → 下单页”三跳路径,如果只靠静态写死 <link rel="prefetch" href="/order.html">,基本等于没做。
as 属性写错等于白加,尤其对 HTML 页面
电商详情页是 HTML 文件,必须显式声明 as="document"。漏掉或写成 as="fetch"、as="json",浏览器会降级为普通链接处理,甚至静默忽略。更麻烦的是:as="document" 会连带加载该 HTML 中所有 <script></script>、<link rel="stylesheet"> 和 <img>,实际流量可能比预估高 3–5 倍。如果详情页含服务端渲染的 nonce 或一次性 token,缓存后的 HTML 渲染时直接校验失败。
静态写死 prefetch 在移动端极易浪费流量
硬编码到模板里的 <link rel="prefetch"> 会无差别触发,哪怕用户只滑了两屏就关掉页面。浏览器不会因跳转或关闭标签而中止请求,后台持续下载直到完成。在 2G 或弱网下,一个 /product/123.html 预取可能吃掉 1.2 MB 流量,而用户根本没点进去。Safari 直到 iOS 16.4 才稳定支持 as="document",旧版 WebView 完全无视,写了也白写。
真正可控的做法:用 IntersectionObserver + 动态注入
把预取时机绑定到用户真实意图上,而不是页面加载完成那一刻:
- 监听商品卡片进入视口(
IntersectionObserver),延迟 200ms 后调用document.createElement('link')注入prefetch - 只预取构建后确定路径的资源,比如 Vite 输出的
/assets/detail.8a2b.js,不预取/product/123这类路由地址(服务端可能返回 404 或重定向) - 同时预取对应 CSS(若分离)和关键字体(但字体更推荐
preload,prefetch不触发 CORS 预检) - 避免对 API 接口(如
/api/cart/add)写prefetch—— 它不发fetch请求,也不解析响应体,只存二进制 blob
复杂点在于:预取的 HTML 必须是静态可缓存的,不能含动态 nonce/token;且 prefetch 本身不提供 JS 可读接口,无法监听是否成功或失败,只能靠 Network 面板查 initiator: prefetch 和跳转后是否命中 200 (from memory cache) 来验证。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











