AudioContext 必须由用户交互激活才能播放,初始化后默认为 suspended 状态,需在 click 或 touchstart 等事件中调用 resume();iOS 仅支持 touchstart/touchend,Android 支持 click 但需确保事件被识别为用户意图;resume 后方可操作节点,且应检查 state 是否为 running。

HTML5 音频播放器在不同环境下(尤其是移动端)常出现“点不动”“没声音”“报错 DOMException”等问题,根源往往不在音频文件或代码逻辑,而在于 AudioContext 的生命周期管理未适配浏览器自动播放策略。关键不是“怎么播”,而是“什么时候能播”。
AudioContext 默认是挂起的,必须由用户交互激活
所有现代浏览器(Chrome、Safari、Firefox、Edge)中,新建的 AudioContext 初始化后状态为 suspended。此时无法创建 Oscillator、调用 start()、decodeAudioData,甚至 currentTime 也不会更新——这是强制机制,不是 bug。
- 必须在用户明确触发的事件中(如
click、touchstart、keydown)调用context.resume() - iOS Safari 要求事件必须是
touchstart或touchend,click在某些版本下无效 - Android Chrome 允许
click,但若页面刚加载完就立即触发,仍可能失败(需确保事件可被识别为“用户意图”) - 不能在
DOMContentLoaded或load回调里 resume,这些不属于用户交互
Web Audio 和 <audio> 标签的激活方式不同
<audio> 元素可通过用户点击直接调用 .play(),而 Web Audio API 必须先激活上下文,再操作节点。两者不能混用同一套逻辑。
- 如果用
createMediaElementSource(audioEl)把<audio>接入 Web Audio,仍需先保证<audio>已成功播放过一次(触发 context resume) - 纯 Web Audio 场景(如 Oscillator、BufferSourceNode),resume 是必经步骤,且只需调用一次
- 建议在首次用户交互回调中统一处理:
if (context.state === 'suspended') context.resume()
避免重复 resume 或误判状态
多次调用 resume 不会报错,但可能掩盖真实问题;而忽略状态检查,直接 start 源节点,就会抛出 DOMException。
立即学习“前端免费学习笔记(深入)”;
- 每次调用
source.start()前,应确认context.state === 'running' - 不要依赖
context.onstatechange监听 resume 结果——它可能在 resume 调用后异步触发,存在时序风险 - 更稳妥的做法:在用户交互事件中先 resume,再立即执行播放逻辑(如
source.start(context.currentTime)) - 若上下文已关闭(
closed),必须新建实例,不能再复用
移动端特殊处理:iOS 和 Android 分开判断
iOS 对用户交互要求最严,Android 各版本行为不一,不能靠 UA 字符串硬匹配,而应结合事件类型和 fallback 策略。
- 优先监听
touchstart(iOS 安全),同时绑定click(Android/桌面兜底) - 对 canvas 或按钮等非表单元素,iOS 需要
{ passive: false }并阻止默认行为,否则 touch 事件可能不触发 - 可加一层防抖:同一事件只 resume 一次,避免快速连点导致冗余调用
- 失败时提示用户“请轻触屏幕以启用声音”,而不是静默失败



















