rel="preload"能抢出400–800ms,因其在解析初期即发起请求,与html解析并行;而需等解析完成才触发下载,此时网络常已被其他资源占用,导致首屏js排队延迟。

rel="preload" 必须用在 SPA 首屏主 Bundle 上,否则下载会晚 400–800ms;但它不是万能药,错配 as、漏写 integrity、混用 modulepreload 或硬编码带 hash 的路径,都会让优化失效甚至变负优化。
为什么 rel="preload" 能抢出 400–800ms
浏览器解析 HTML 时,<link rel="preload" href="main.js" as="script"> 在 开头就被扫描并立即发起请求,和 HTML 解析并行;而 <script type="module" src="main.js"></script> 要等整个 解析完、遇到该标签才触发下载——此时网络可能已被 CSS、字体占满,首屏 JS 下载被迫排队。
- 实测中,3G 网络下
main.js的Start Time可提前 400–800ms - 必须放在
最早位置,早于所有<script></script>和<link rel="stylesheet"> - 不能用
<script src="main.js"></script>替代——它会阻塞 HTML 解析,且无法控制优先级
as="script" 是硬门槛,不是可选项
漏写或写错 as 属性,rel="preload" 就等于没写:Chrome Network 面板里 Priority 显示为 Low,和普通 fetch 无异;更糟的是,后续 <script src="main.js"></script> 仍会重新发起一次请求,造成重复下载。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 必须写
as="script",不能是as="fetch"、as="module"或留空 - 如果主入口是
type="module"且带integrity(如integrity="sha256-..."),则 preload 标签也必须带完全相同的integrity值,否则缓存不复用 - 服务端返回的 MIME 类型必须是
application/javascript,Safari/Edge 否则可能拒绝执行
用 rel="modulepreload" 还是 rel="preload"?看模块加载方式
如果你的 main.js 是 ES 模块(type="module"),且内部有静态 import 链(比如 import { render } from './core.js'),只用 rel="preload" 不够:它只下载 main.js,子模块仍要等解析后才请求,多轮 RTT 延迟明显。
- 改用
<link rel="modulepreload" href="main.js">:它会预解析main.js并递归预取所有静态import的依赖(如core.js、router.js) -
modulepreload不允许加as属性,加了会被忽略 -
href必须和import()或type="module"中写的路径完全一致(包括查询参数,如?v=1.2) - 多个
modulepreload标签之间无顺序依赖,但必须全部出现在首个模块脚本之前
构建产物路径变动会让 preload 失效
Webpack/Vite 默认给 JS 文件加 hash(如 app.a1b2c3.js),每次构建路径都变,导致 rel="preload" 缓存失效、重复下载,甚至 404。
- 对首屏关键 Bundle,建议禁用 hash 或固定文件名(如
main.js) - 或通过构建插件将真实路径注入 HTML 模板:Vite 可配
build.rollupOptions.output.entryFileNames;Webpack 可配output.filename+HtmlWebpackPlugin动态注入 - 绝对不要在 HTML 中硬编码带 hash 的路径,上线后 preload 指向 404
-
rel="preload"只对当前页有效,页面跳转后预加载即终止,缓存也不跨会话复用——想预加载下一页资源,必须用rel="prefetch"
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










