浏览器无bufferedupdate事件,可靠方式仅有timeupdate监听或每300ms轮询video.buffered;需确保readystate≥have_future_data后读取,正确计算缓冲百分比须处理currenttime越界、duration为infinity及buffered.length为0三类边界。

不能直接监听缓冲区更新,因为浏览器没有 bufferedupdate 这类标准事件——Chrome 曾短暂支持,但自 2023 年起已移除。真正可靠的方式只有两种:利用 timeupdate 事件,或主动轮询 video.buffered。而加载等待的提示,需结合事件状态与缓冲数据综合判断,避免误触发。
用 timeupdate 或轮询读取 buffered 数据
video.buffered 是唯一可信的缓冲信息来源,但它不能被“监听”,只能被“读取”。关键点有三个:
- 必须等
video.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA才能安全访问,否则可能返回空区间或NaN - 首次可读时机是
loadedmetadata或canplay触发后,此时buffered.length才有意义 - 推荐每 300ms 主动轮询一次
video.buffered,比依赖timeupdate更稳定——尤其在暂停、静音或拖拽后,timeupdate可能停发,但缓冲仍在后台进行
正确计算已缓冲百分比
直接用 buffered.end(0) / duration * 100 算百分比,在真实场景中极易出错。必须处理三类边界情况:
- 当前播放时间
currentTime超出所有已缓冲区间 → 返回0(不是负数,也不抛错) -
duration === Infinity(如直播流)→ 百分比无意义,应改算“还能往回拖多少秒”,即buffered.end(i) - currentTime -
buffered.length === 0→ 直接返回0,别调用end(0),否则会触发IndexSizeError
参考实现逻辑:
function getBufferedPercent(video) {
const time = video.currentTime;
let bufferedEnd = 0;
for (let i = 0; i if (video.buffered.start(i) bufferedEnd = video.buffered.end(i);
break;
}
}
return video.duration ? Math.min(100, (bufferedEnd / video.duration) * 100) : 0;
}
显示加载等待要防误判和抖动
仅靠 waiting 事件显示“缓冲中”容易误判(比如低网速下频繁触发)。建议叠加判断:
-
video.networkState === HTMLMediaElement.NETWORK_LOADING:说明资源还在下载中 video.buffered.length > 0 && video.buffered.end(0) :已有缓冲但不够播,确实在卡- 配合
stalled事件,可区分是网络超时还是解码瓶颈
UI 层面,缓冲数值本身波动剧烈(如一秒内 45% → 38% → 52%),直接渲染会导致肉眼可见抖动。最轻量做法是维护长度为 3 的滑动窗口,每次新值进来取平均,平滑显示。
预加载与服务端配置影响缓冲体验
很多卡顿其实源于初始加载策略和服务端支持不足:
-
preload="auto"是首选(注意不是"true"或"yes"),但 iOS Safari 在蜂窝网络下基本无视它,只在 Wi-Fi 下可能生效 - 若流量敏感,可用
preload="metadata"+ 用户 hover 时调用video.load()主动触发加载 - 确保服务端开启 HTTP Range 请求:响应头含
Accept-Ranges: bytes,且视频请求带Range: bytes=0-;Nginx 需启用 range 模块,对象存储要打开“分段下载” - 千万别用 gzip 压缩 MP4 文件——破坏字节对齐,导致 416 错误,反而阻断缓冲
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











