元素不主动发起请求,超时由浏览器内部静默处理;无法直接监听加载失败,需通过 loadedmetadata 后检查 textTracks.length 或用 fetch 探测;重试须移除旧元素、新建带时间戳 src 的 并插入,再手动设 mode = 'showing'(需等待 readyState === 2)。

track 元素本身不触发 fetch,超时不是它的问题
<track></track> 标签只是声明一个外部文本轨道资源(如 .vtt),它不会主动发起网络请求;真正加载行为由浏览器在 <video></video> 或 <audio></audio> 播放时按需触发,且完全不可控、无 Promise、无 abort 机制。你看到的“超时”,其实是浏览器内部加载 src 地址失败后静默放弃——没有错误事件、不抛异常、也不触发 onerror。
如何感知 track 加载失败
目前没有标准 API 能直接监听 <track></track> 加载结果。可行的间接判断方式只有两个:
- 监听
<video></video>的loadedmetadata事件后,检查video.textTracks.length是否符合预期(比如你声明了 2 个<track></track>,但length === 0或=== 1) - 对每个
<track></track>的src单独用fetch()探测(带AbortSignal.timeout(5000)),失败即视为轨道不可用
注意:textTracks[i].mode === 'disabled' 不代表加载失败,可能只是用户手动关闭;mode === 'showing' 才说明已就绪并启用。
重试必须绕过 track 标签,用 JS 动态替换
浏览器不提供重试接口,唯一可靠方式是:移除旧 <track></track>,创建新元素并插入,强制触发新加载。关键操作包括:
立即学习“前端免费学习笔记(深入)”;
- 先设
trackElement.remove(),不能只改src - 新建
document.createElement('track'),完整复制kind、srclang、label、default等属性 -
src值末尾加时间戳或随机查询参数(如?t=1730110515),防止浏览器复用缓存的失败响应 - 插入到原
<video></video>中,再调用video.load()或等待下一次播放触发加载
示例代码片段:
const oldTrack = video.querySelector('track[src="sub.vtt"]');<br>if (oldTrack) {<br> oldTrack.remove();<br>}<br>const newTrack = document.createElement('track');<br>newTrack.kind = 'subtitles';<br>newTrack.srclang = 'zh';<br>newTrack.label = '中文';<br>newTrack.src = 'sub.vtt?t=' + Date.now();<br>video.appendChild(newTrack);
为什么不能用 onerror 或 window.addEventListener('error')
<track></track> 不支持 onerror 属性,也**不会**在 window 上抛出可捕获的 ErrorEvent。全局 error 事件监听到的错误来自脚本、图片或 <script></script>,与 <track></track> 无关。试图监听它只会浪费调试时间。
真正容易被忽略的是:即使你成功重试并插入新 <track></track>,浏览器也不会自动启用它——除非用户手动在视频控件里选择,或你通过 textTracks[i].mode = 'showing' 显式激活。而这个操作必须等 textTracks[i].readyState === 2(loaded)之后才安全,否则会静默失败。



















