ontimeupdate事件在audio/video的currenttime变化时高频触发,需在loadedmetadata后绑定并节流防抖,匹配时用容差避免精度问题。

ontimeupdate 事件什么时候触发
ontimeupdate 是 <audio></audio> 和 <video></video> 元素的原生事件,只要 currentTime 发生变化就会触发——包括播放中、拖动进度条、调用 play() 或 pause() 后恢复播放等场景。它不是“每秒一次”,而是高频触发(通常 200–250ms 一次),适合做实时同步,但不适合直接绑定耗时操作。
为什么不能一加载就绑 ontimeupdate
常见错误是页面一拿到 <video></video> 元素就立刻加监听:
const video = document.getElementById('myVideo');
video.ontimeupdate = handleTimeUpdate; // ❌ 可能失效
此时 video.duration 往往还是 NaN,currentTime 可能为 0 或未就绪,导致匹配逻辑出错或白屏。必须等元数据加载完成:
- 用
loadedmetadata事件确保duration、videoWidth等可用 - 用
canplay或canplaythrough则更稳妥(尤其网络较慢时) -
loadeddata只保证第一帧画面就绪,不保证duration已知,慎用
怎么写一个安全的 timeupdate 监听器
推荐用 addEventListener,避免覆盖已有监听;同时在回调里做防抖或节流(尤其匹配歌词/字幕时):
const video = document.getElementById('myVideo');
video.addEventListener('loadedmetadata', () => {
video.addEventListener('timeupdate', () => {
const t = video.currentTime;
// 避免每 200ms 都重绘:只在跨行时更新
if (Math.floor(t) !== Math.floor(lastShownSecond)) {
updateLyrics(t);
lastShownSecond = Math.floor(t);
}
});
});
- 不要在
timeupdate回调里频繁 DOM 操作(如反复innerHTML) - 歌词匹配建议倒序遍历时间戳数组,找最后一个
time ≤ currentTime的项 - 若用
requestAnimationFrame替代timeupdate,需自行读取currentTime,且无法响应拖动跳转
容易被忽略的兼容性和精度问题
currentTime 是浮点数,但实际精度受编码和浏览器限制,可能有毫秒级偏差。比如某行歌词标的是 15.60,但实际触发时可能是 15.602 或 15.598。所以匹配逻辑别用严格相等:
// ❌ 错误
if (lyric.time === currentTime) { ... }
<p>// ✅ 正确:允许 ±50ms 容差
if (Math.abs(lyric.time - currentTime) </p>
- 移动端 Safari 对
timeupdate触发频率更保守,有时会“跳帧” - 后台标签页中,Chrome 会降频触发(甚至暂停),
visibilitychange事件需配合处理 - 如果视频源是 HLS 或 MSE 流,
duration可能动态变化,timeupdate仍有效,但需监听durationchange
真正麻烦的不是绑事件,而是怎么让每次触发都稳定、轻量、不卡顿。尤其当你要同步高亮、滚动、动画、甚至发送埋点时,得先守住 currentTime 的可信区间,再决定要不要动 DOM。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











