
speechSynthesis.getVoices() 返回空数组怎么办
初始化失败最常见原因不是 API 不可用,而是语音列表还没加载完成就调用了 getVoices()。Chrome、Edge 和新版 Safari 都会异步加载语音数据,首次调用时返回空数组是正常行为。
- 必须监听
voiceschanged事件,而不是立即执行合成 - 不要在页面加载完成(
DOMContentLoaded)后立刻查语音列表,要等事件触发 - 某些浏览器(如旧版 Safari)需要用户交互(比如点击)后才允许加载语音,静默初始化必然失败
示例:
speechSynthesis.onvoiceschanged = () => {
const voices = speechSynthesis.getVoices();
if (voices.length > 0) {
speak(voices[0]); // 此处再开始合成
}
};
SpeechSynthesis.speak() 调用后没声音的典型场景
不是所有 speak() 调用都会出声——它受当前上下文状态严格限制。静音、暂停、正在播放其他语音、或未设置有效 voice 都会导致无声。
- 检查
speechSynthesis.pending、speechSynthesis.speaking、speechSynthesis.paused三个状态,任一为true都可能阻塞新语音 - 必须显式赋值
utterance.voice,即使只有一种语音可用;不设则默认使用系统 fallback,而某些环境 fallback 为空或无效 - 移动端 iOS Safari 对自动播放限制极严,无用户手势触发的
speak()会被静音且不报错
Chrome 中 speechSynthesis 初始化失败但控制台无报错
Chrome 不会抛异常,但会在后台拒绝初始化——尤其当页面被标记为“非活跃标签页”或处于后台时。这不是 bug,是主动的资源节流策略。
- 检查
document.visibilityState === 'visible',隐身/后台标签页中getVoices()可能延迟数秒甚至不触发voiceschanged - 避免在 Service Worker 或 iframe(尤其是 sandboxed)中调用,这些上下文不支持语音合成 API
- 企业环境或某些 Chrome 策略(如
SpeechRecognitionEnabled被禁用)也会连带关闭speechSynthesis
utterance.onerror 里捕获不到“没声音”的错误
onerror 只响应明确失败(如非法语音 ID、文本超长),而“无声”绝大多数时候是静默失败:API 接受了请求,但没调度到音频引擎。
立即学习“前端免费学习笔记(深入)”;
- 不能依赖
onerror判断是否发声成功,要结合onstart和onend实际观察回调是否触发 - 调试时优先用
console.log(speechSynthesis)查看speaking和pending实时值,比看错误更可靠 - 某些安卓 WebView(如微信内置)会假性触发
onstart却无音频输出,需额外加 audio context 检测或 fallback 提示
语音合成不是“调了就响”,它高度依赖浏览器状态、用户意图和系统音频策略。最容易被忽略的是:你写的那行 speak(),可能根本没进到音频管线里——先确认它真的被调度了,再排查内容或设备问题。











