as="script"专用于动态加载场景,告诉浏览器该资源将通过document.createElement('script')或import()等方式以脚本形式使用,需按脚本优先级预处理;它不执行脚本,也不替代<script defer>或<script type="module">,且必须与实际加载方式严格匹配路径和crossorigin属性,否则可能404、被忽略或触发重复请求。

preload 的 as="script" 是给谁用的
as="script" 告诉浏览器:这个资源后续会以 <script> 方式加载(比如通过 document.createElement('script') 或 import()),请按脚本的优先级、CSP 策略和解析规则预处理它。
它**不等于**直接执行脚本,也不替代 <script defer> 或 <script type="module">。常见于动态 import 场景,比如路由懒加载、功能模块按需加载。
典型误用是把它配给一个普通 <script src="..."></script> —— 这时浏览器已自行识别为脚本,preload 反而可能触发重复 fetch 或 CSP 冲突。
怎么写才不会 404 或被忽略
preload 的 as 值必须与实际使用方式严格匹配,否则浏览器会降级为普通 fetch(无优先级提升),甚至拒绝解析。
-
href 路径必须准确指向最终 JS 文件(不能是打包器生成的占位符路径,比如 Webpack 的 chunk-xxx.js 若未固定 hash 就容易失效)
-
crossorigin 属性必须与脚本实际加载方式一致:如果脚本跨域且带凭证(如 cookies),必须加 crossorigin="use-credentials";若只是跨域不带凭证,用 crossorigin(空值);同域可省略
- 不能省略
as —— 没有 as 的 preload 对 JS 几乎无效,浏览器无法决定如何预处理
<link rel="preload" href="/js/chart.js" as="script" crossorigin>
和 prefetch、preconnect 混用时的优先级陷阱
preload 是高优先级资源获取,但它的执行时机仍由 JS 主动控制。如果同时写了:
<link rel="preload" href="/js/worker.js" as="script">
<link rel="prefetch" href="/js/worker.js">
浏览器可能把同一资源 fetch 两次 —— 因为 prefetch 是低优先级后台加载,和 preload 不共享缓存决策。更糟的是,某些旧版 Chrome(≤90)在 preload + prefetch 同 URL 时会跳过 preload。
href 路径必须准确指向最终 JS 文件(不能是打包器生成的占位符路径,比如 Webpack 的 chunk-xxx.js 若未固定 hash 就容易失效)crossorigin 属性必须与脚本实际加载方式一致:如果脚本跨域且带凭证(如 cookies),必须加 crossorigin="use-credentials";若只是跨域不带凭证,用 crossorigin(空值);同域可省略as —— 没有 as 的 preload 对 JS 几乎无效,浏览器无法决定如何预处理prefetch、preconnect 混用时的优先级陷阱
preload 是高优先级资源获取,但它的执行时机仍由 JS 主动控制。如果同时写了:
<link rel="preload" href="/js/worker.js" as="script"> <link rel="prefetch" href="/js/worker.js">浏览器可能把同一资源 fetch 两次 —— 因为
prefetch 是低优先级后台加载,和 preload 不共享缓存决策。更糟的是,某些旧版 Chrome(≤90)在 preload + prefetch 同 URL 时会跳过 preload。
建议:只用 preload,不用 prefetch 配 JS;若需预连接 CDN,单独用 preconnect:
<link rel="preconnect" href="https://cdn.example.com">
动态 import 场景下怎么配合 as="script"
这是 as="script" 最实用的场景:提前 fetch 模块,等用户操作(如点击按钮)再 import(),减少首屏阻塞。
关键点:
-
preload必须在import()调用前就存在 DOM 中(最好放在<head>里) -
import()的路径要和href完全一致(包括 query 参数,如?v=1.2) - ESM 动态 import 自动识别预加载资源;但 CommonJS 的
require.ensure或自定义 loader 不会利用它
<link rel="preload" href="/js/analytics.mjs" as="script">
<script>
button.addEventListener('click', () => {
import('/js/analytics.mjs').then(mod => mod.init());
});
</script>
真正容易被忽略的是:预加载资源一旦进入内存,就“绑定”到该 URL 字符串。如果构建时用了 contenthash,但 HTML 模板里写的还是旧 hash,preload 就变成无效请求——既不加速,还浪费带宽。



















