rel="preload"不支持as="track",所有主流浏览器均无效;应改用rel="prefetch" as="fetch"或JS主动fetch预加载WebVTT字幕,并配合服务端强缓存、压缩与Accept-Ranges支持。

track元素本身不能被rel="preload"
浏览器不支持 rel="preload" + as="track"——这个组合在所有主流引擎里都无效。as 值列表里根本没有 track,写了等于没写,Network 面板里会显示 Priority 为 Low、Initiator 是 (Other),和普通 fetch 无异。W3C 规范也没定义它,所以别在 里塞这种标签。
真正能提前加载 WebVTT 字幕文件的方法只有两种
WebVTT 是纯文本资源,必须走 HTTP 请求加载,而浏览器只会在解析到 <track></track> 标签、且视频进入可播放状态(或用户交互触发)后才发起请求。慢网下等它现场拉,字幕必然延迟甚至空白。可行路径只有:
- 用
<link rel="prefetch" as="fetch" href="/sub/en.vtt" crossorigin>:放在里,as="fetch"是唯一合法匹配项;必须加crossorigin(即使同源),否则 Chrome/Safari 拉下来也不会缓存复用 - JS 主动预载:
fetch('/sub/en.vtt', { credentials: 'same-origin' }).then(r => r.text()),拿到内容后暂存,等<video></video>就绪再动态注入<track kind="subtitles"></track>并设src为空字符串再赋值,避免重复请求
注意:prefetch 不保证执行,它只在 window.onload 后空闲时低优下载;若用户快速跳转或网络受限(如省流模式),可能直接跳过。
为什么不能用 new Video().addTextTrack() 或 preload="metadata"
addTextTrack() 只创建空 track 对象,不发起任何网络请求;preload="metadata" 对 <video></video> 有效,但对关联的 <track></track> 完全无影响——浏览器根本不会因此提前拉 VTT 文件。实测中,哪怕 video.readyState === 1 (HAVE_METADATA),<track></track> 的 readyState 仍是 0,直到它自己被触发加载。
立即学习“前端免费学习笔记(深入)”;
更隐蔽的问题是:如果多个 <track></track> 共享同一 URL(比如语言切换),但没做去重,浏览器可能并发拉多次,尤其在 JS 动态切换时。务必用 Map 缓存已加载的 VTT 内容,按 src 字符串做 key。
服务端配合才能稳住慢网体验
光前端预载不够。VTT 文件必须满足三个条件,否则预载回来也白搭:
- 响应头含
Accept-Ranges: bytes:允许浏览器断点续传,弱网中断后能续,而不是重头拉 - 带强缓存策略:
Cache-Control: public, max-age=31536000,确保 prefetch 或 fetch 的结果能复用,不因刷新失效 - 压缩传输:
Content-Encoding: br或gzip,典型英文字幕 VTT 压缩后常低于 5KB,比未压缩快 3~5 倍
最后提醒一句:别在 HTML 里写 <track src="sub/en.vtt"></track> 同时又用 JS 去 fetch 同一地址——Safari 会双下,Chrome 可能因缓存键不一致而重复请求。要么全托管给 JS,要么全交给原生 track,二者不可混用。



















