HTML5 Web Audio API 的核心是基于 AudioContext 构建有向音频图,所有定时操作须依赖其高精度 currentTime 时钟,且必须在用户手势事件中初始化;音频节点单向连接,媒体元素需通过 createMediaElementSource 接入,参数自动化采用指数曲线实现自然淡入淡出。

HTML5 Web Audio API 处理音频流的核心,是构建并调度一个由节点组成的有向音频图(Audio Routing Graph),所有操作都围绕 AudioContext 展开——它不是播放器,而是整个音频系统的运行时环境和时间基准。
AudioContext 是音频处理的唯一入口和时间中枢
每个页面只能有一个活跃的 AudioContext 实例,它提供高精度的内部时钟(currentTime),所有音量变化、延迟触发、滤波切换等定时操作都必须基于这个时钟,不能依赖 setTimeout 或 requestAnimationFrame。用户手势(如 click、touchend)是启动上下文的硬性前提;未交互前创建的 context 默认处于 suspended 状态,后续节点连接和参数调度都会静默失败。
- 初始化必须在用户事件回调中:
button.addEventListener('click', () => { audioContext = new (window.AudioContext || window.webkitAudioContext)(); }); - 若需预加载,可先创建后立即
audioContext.suspend(),交互时再audioContext.resume() - 所有时间敏感操作(如淡入、跳转、混响触发)都用
audioContext.currentTime + X计算目标时刻
音频节点按功能分层,连接形成单向数据流
音频从源节点出发,经若干中间处理节点,最终流向 audioContext.destination(即扬声器)。节点之间是单向、无环的连接关系,类似调音台信号路径:源 → 效果链 → 输出。中间节点不存储音频,只实时变换流数据。
-
源节点:可以是
createMediaElementSource(audio)(对接 HTML5<audio></audio>)、createOscillator()(合成波形)、createMediaStreamSource(stream)(麦克风或屏幕共享流) -
处理节点:如
GainNode(音量/淡入淡出)、BiquadFilterNode(高低通/共鸣)、DelayNode(回声)、ConvolverNode(卷积混响)、AnalyserNode(频谱分析) -
输出节点:固定为
audioContext.destination,不可替换
媒体元素接入必须走 createMediaElementSource
想用 Web Audio API 控制一个已有的 <audio></audio> 标签(比如带 controls 的播放器),不能直接操作其 .volume 或监听 timeupdate 来驱动效果——这些属于 DOM 层控制,与音频图无关。正确方式是用 createMediaElementSource 将其“桥接”进音频图,使播放、暂停、seek 等状态变化自动反映在音频流中,同时保留对音量、滤波等的精细调度能力。
立即学习“前端免费学习笔记(深入)”;
- 错误做法:
audio.volume = 0.3—— iOS/Safari 下常被拦截,且无法实现平滑淡入 - 正确做法:
const source = audioContext.createMediaElementSource(audio); source.connect(gainNode); gainNode.connect(audioContext.destination); - 此后所有音效、可视化、动态调节都通过 gainNode.gain 等参数自动化完成
参数自动化是实现专业音频行为的关键
Web Audio API 不靠轮询或定时器改变参数,而是使用基于时间轴的自动化方法。例如淡入淡出必须用 exponentialRampToValueAtTime,因为人耳对音量感知呈对数关系,指数曲线比线性更自然;起始值不能设为 0,需用极小值(如 0.001)避免爆音。
- 淡入两秒:
gainNode.gain.setValueAtTime(0.001, ctx.currentTime); gainNode.gain.exponentialRampToValueAtTime(1, ctx.currentTime + 2); - 淡出并在结束时截断残留:
gainNode.gain.exponentialRampToValueAtTime(0.001, now); gainNode.gain.cancelAndHoldAtTime(0.001, now); - 跳转播放位置后,必须重新计算当前
currentTime并重设 ramp 起点,否则时间错位



















