video error事件后重试无限循环,因onerror是一次性钩子且未清空src或限制次数;应依据error.code(2可重试、3/4不可)判断,并每次重试前置空src、用dataset.retryCount限3次、检查readyState

video 的 error 事件触发后为什么重试会无限循环
因为 onerror 是一次性钩子,但很多人在 handler 里直接改 video.src,没清空旧值,浏览器发现 URL 没变,就跳过请求,也不触发新 error,但也没成功——于是你手动再点重试、再设 src,形成人为循环。更糟的是,如果重试逻辑写在 onerror 属性里(如 onerror="retry(this)"),每次失败都执行一遍,却没做次数限制或状态标记,就会真跑出无限递归。
如何用 code 值判断是否值得重试
video.error.code 才是关键依据,不是所有错误都该重试:
-
video.error.code === 2(MEDIA_ERR_NETWORK):网络问题,可重试;先用fetch(video.currentSrc, { method: 'HEAD' })验证 URL 是否可达 -
video.error.code === 4(MEDIA_ERR_SRC_NOT_SUPPORTED):格式不支持,换<source></source>或降级 MP4,别 retry 同个地址 -
video.error.code === 3(MEDIA_ERR_DECODE):解码失败(如 Safari 加载 AV1),重试毫无意义,应切换编码格式 - code 为
1(MEDIA_ERR_ABORTED)或0(无错误)时,通常不是加载失败,不用干预
停止重试的三个硬性操作
缺一不可,否则逻辑会失控:
- 每次重试前必须先设
video.src = '',再赋新值,否则浏览器缓存失败响应,不发新请求 - 用独立变量(如
video.dataset.retryCount)按实例计数,不是全局计数;重试上限设为 3,到第 3 次后设video.onerror = null彻底断开钩子 - 重试函数里要检查
video.readyState ,即还没进入 <code>HAVE_NOTHING状态,说明上一次加载还没真正结束,此时重试会冲突
动态创建 source 时怎么避免重复绑定 error
不要给每个 <source></source> 写 onerror——它不触发,且无法捕获。真正有效的做法是监听 <video></video> 的 error,然后根据 video.currentSrc 匹配备用源:
立即学习“前端免费学习笔记(深入)”;
- 把备用地址存在
video.dataset.fallbackUrls里,JSON 格式,如'["/v.mp4", "/v.webm"]' - 在
error回调里解析这个数组,取下一个 URL,同时更新dataset.retryIndex - 如果索引超了数组长度,就停掉重试,显示 fallback UI,不再碰
src
最容易被忽略的是:error 事件只在加载阶段触发,播放中卡顿、花屏、音画不同步完全不会触发它。一旦误以为“有 error 就代表视频坏了”,就会在不该重试的时候狂刷 src,反而阻塞后续加载。



















