audio.duration在loadedmetadata事件后才有效,currentTime写入需音频就绪;timeupdate事件存在节流与竞态问题,应结合raf轮询和状态管理;play()需捕获Promise拒绝,播放状态须综合事件与readyState判断。

能实时显示进度,但必须手动监听事件、主动读取属性,浏览器不会自动同步更新 DOM。
audio.currentTime 和 audio.duration 什么时候可读?
这两个值不是随时都能用的:
-
audio.duration在loadedmetadata事件触发后才有效,之前是NaN;直接在页面加载完就取,大概率拿到NaN -
audio.currentTime在音频未加载或未就绪时写入(比如调play()前就设),会被忽略或静默失败 - Safari 对
currentTime的精度会四舍五入到毫秒级,设12.345可能实际跳到12.346 - 移动端某些 WebView(如微信内嵌)在后台切回时,
currentTime可能滞后于真实播放位置,需结合timeupdate+requestAnimationFrame补偿
用 timeupdate 事件更新进度条的坑
很多人以为绑个 timeupdate 就万事大吉,但实际表现常卡顿或跳变:
- 该事件不是每帧触发,Chrome 下约 200–250ms 一次,Firefox 更稀疏;纯靠它驱动 UI 会有明显延迟
- 用户拖拽进度条时,
timeupdate仍会持续触发,和你手动设置currentTime形成竞态,导致进度条“弹回”旧位置 - 正确做法是:拖拽开始时暂停监听
timeupdate,拖拽结束再恢复;或者用requestAnimationFrame主动轮询,避开事件节流 - 别在
timeupdate回调里直接操作 DOM 样式(比如改width),应先存进变量,统一用raf批量更新
播放状态(playing/paused/ended)怎么准确判断?
不能只看 audio.paused 或 audio.ended,它们只是快照,且有盲区:
立即学习“前端免费学习笔记(深入)”;
-
audio.paused === true不代表“用户点了暂停”,也可能是加载失败、被系统中断(如来电)、或play()被拒绝后留下的状态 -
audio.ended为true后,如果没重置currentTime = 0,下次play()会立刻结束——这是常见“点一下就停”的原因 - 真正可靠的判断依据是组合事件:
play、pause、ended、abort、error,并配合readyState(如HAVE_ENOUGH_DATA)过滤无效状态 - 注意
play()返回 Promise,Chrome/Firefox/Safari 都可能 reject,必须.catch()捕获NotAllowedError,否则后续逻辑全断
进度条不是画一条线的事,它是时间轴映射 + 状态机 + 事件调度的混合体。最容易被忽略的是:所有读写操作都得和 readyState、networkState 对齐,否则你看到的“当前时间”可能根本还没加载进来。



















