必须在用户手势(如click)中首次调用play(),后续靠ended等事件链式触发;复用Audio实例需重新load;MediaSession可增强状态同步与错误处理;Web Audio仅适用于高精度场景。

怎么用 Audio 对象顺序播放多个音频文件
浏览器原生 Audio 不支持直接传入数组或播放列表,必须手动监听 ended 事件来触发下一个。靠 play() 链式调用会失败——因为后续的 play() 没有用户手势上下文,会被浏览器静音拦截。
- 只在用户点击/触摸后调用第一个
play(),后续靠事件驱动 - 每个新
Audio实例都要单独load()(尤其 Safari 对复用实例不友好) - 别用
setTimeout模拟顺序——网络延迟、解码耗时会让节奏错乱 - 示例:
const list = ['a.mp3', 'b.mp3', 'c.mp3'];
let i = 0;
function playNext() {
if (i >= list.length) return;
const audio = new Audio(list[i++]);
audio.onended = playNext;
audio.play().catch(e => console.warn('play failed:', e));
}
button.addEventListener('click', playNext);
为什么 MediaSession + Audio 能让播放列表更可靠
单纯靠 ended 事件容易漏掉错误中断(如 404、解码失败、暂停后恢复),MediaSession 不仅能同步系统媒体控件,还能把播放状态显式暴露出来,方便补救。
- 必须在用户手势后调用
navigator.mediaSession.setActionHandler('nexttrack', ...),否则无效 -
mediaSession.metadata要每次播放前更新,否则锁屏界面显示旧信息 - 监听
error和abort事件比只盯ended更稳妥 - Safari 要求
mediaSession在play()前设置,Chrome 则宽松些
Web Audio API 适合做无缝切换但没必要硬上
如果只是播语音、播 podcast、播背景音乐,Audio + 事件就足够;只有当你需要毫秒级衔接、实时音效叠加、或动态变速变调时,才值得切到 Web Audio API。
-
AudioBufferSourceNode播完自动销毁,不能 reuse,得重新 decode - 用
context.currentTime算调度时间,比依赖事件更准,但开发成本高一倍 - 移动端 iOS Safari 对 Web Audio 的自动播放限制更严,常需额外唤醒逻辑
- 普通顺序播放场景下,强行上 Web Audio 只会增加兼容性风险和调试难度
常见报错 DOMException: play() failed because the user didn't interact with the document first 怎么绕
这个错误不是 bug,是浏览器策略。核心原则:所有 play() 必须发生在用户触发的同步回调内(比如 click、touchstart),且不能包在 Promise.then、setTimeout 或异步加载完成回调里。
- 首次播放必须由用户真实点击启动,不能靠自动触发或模拟 click
- 后续播放可以放在
ended、canplay这类同步触发的事件里(它们属于用户交互的“延续”) - 如果音频源是动态生成的(比如 Blob URL),确保
createObjectURL在用户交互后调用 - 测试时别用
location.reload()后立刻自动播——重载不算用户交互,得再点一次










