
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个语音(如 Microsoft 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();⚠️ 注意事项:
- 不要依赖 setTimeout 替代事件监听:setTimeout(…, 100) 是不可靠的“魔法数字”,不同设备/网络下语音加载时间差异大;
- once: true 选项防止重复绑定:避免多次触发导致重复播报;
- 始终校验 voices.length:索引访问前必须判断数组长度,否则可能报 Cannot set property 'voice' of undefined;
- 跨浏览器兼容性:Firefox、Chrome、Edge 均支持 voiceschanged,但 Safari(iOS/macOS)对 Web Speech API 支持有限(仅部分版本支持且需用户授权),生产环境建议添加特性检测与降级提示。
总结:getVoices() 的“空数组陷阱”本质是异步资源加载时序问题。拥抱事件驱动模型,以 voiceschanged 为守门人,即可稳定、可维护地控制语音合成行为。









