贝利信息

SpeechSynthesis.getVoices() 返回空数组的解决方案

日期:2026-01-26 00:00 / 作者:聖光之護

speechsynthesis api 的 `getvoices()` 方法在页面加载初期常返回空数组,因其语音列表异步加载;需监听 `voiceschanged` 事件确保语音就绪后再获取并设置 voice。

SpeechSynthesis.getVoices() 并非同步阻塞方法——它立即返回当前已加载的语音列表,而浏览器语音引擎(如 Chrome 的本地 TTS 或系统语音服务)通常在页面加载后异步初始化并注入可用语音。因此,若在脚本执行早期(例如

✅ 正确做法是:始终通过 speechSynthesis.onvoiceschanged 事件(或 addEventListener("voiceschanged", ...))监听语音就绪时机。该事件会在语音列表首次加载完成或后续动态更新(如系统新增语音)时触发,是唯一可靠的同步点。

以下是推荐的健壮实现方式:

function speakWithCustomVoice() {
  const msg = new SpeechSynthesisUtterance("Hello World!");

  // 确保语音已加载
  function setAndSpeak() {
    const voices = speechSynthesis.getVoices();

    // 安全检查:避免越界访问
    if (voices.length > 2) {
      msg.voice = voices[2]; // 例如选择第3个语音(如 Micro

soft Linda) speechSynthesis.speak(msg); } else { console.warn("未检测到足够多的语音,使用默认语音播放"); speechSynthesis.speak(msg); } } // 首次监听 voiceschanged speechSynthesis.addEventListener("voiceschanged", setAndSpeak, { once: true }); // 兜底处理:若事件未触发(极罕见),延迟重试(可选) setTimeout(() => { if (speechSynthesis.getVoices().length === 0) { console.warn("警告:voiceschanged 事件未触发,尝试手动重试"); setAndSpeak(); } }, 1000); } speakWithCustomVoice();

⚠️ 注意事项:

总结:getVoices() 的“空数组陷阱”本质是异步资源加载时序问题。拥抱事件驱动模型,以 voiceschanged 为守门人,即可稳定、可维护地控制语音合成行为。