Web Speech API 到底能做什么
如果你翻过 Web Speech API 的文档,第一反应多半是:这么简单的接口,怎么就没多少人用在生产环境里。语音识别一个小对象挂几个回调,语音合成一行代码就能让页面开口说话。可真到了接需求的时候,你会发现事情远不止 API 本身。

Web Speech API 实际上由两个独立的部分组成:SpeechRecognition 负责语音识别,把麦克风里的语音转成文字;SpeechSynthesis 负责语音合成,把文字转换成语音播放出来。它们虽然被归在同一个规范下,但实现状态和稳定程度差别非常大。如果不理解这一点,开发过程中很容易被兼容性问题拖住。
很多团队第一次接触它,是做一个“语音搜索”原型或者给文章加一个“朗读”按钮。我见过不少项目,在 Chrome 里演示得很顺利,一旦换到真实用户环境就完全不能用。这不是 API 本身难写,而是我们忽略了它背后的运行条件和限制。这篇文章就从这两个接口的实战用法开始,结合我在浏览器端落地语音功能的经验,把常见的坑和取舍讲清楚。
语音识别:SpeechRecognition 的实战写法
SpeechRecognition 的基础用法不难,核心是创建一个识别实例,配置语言和结果返回方式,然后监听事件。下面这段代码是我在项目里使用的一个最小可用版本,支持中文、持续识别和中间结果输出。
const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
recognition.lang = 'zh-CN';
recognition.continuous = true;
recognition.interimResults = true;
recognition.onresult = (event) => {
let finalText = '';
const len = event.results.length;
for (let i = event.resultIndex; i < len; i++) {
if (event.results[i].isFinal) {
finalText += event.results[i][0].transcript;
}
}
if (finalText) {
console.log('识别结果:', finalText);
}
};
recognition.onerror = (event) => {
console.error('识别出错:', event.error);
};
recognition.onend = () => {
// 连续识别场景,结束后需要主动重启
recognition.start();
};
recognition.start();
这段代码里有几个关键点要留意。lang 设置为 ‘zh-CN’ 是希望识别中文,但不同浏览器对这个参数的支持力度不一样;continuous 表示持续识别,但设置为 true 并不代表永远不会停止,很多实现会在一段时间没有语音或网络波动后自动 end;interimResults 允许我们在用户还没说完时就拿到临时结果,这是做实时反馈的基础。
在 onend 里直接调用 recognition.start() 是我比较推荐的重启方式。原因很简单:浏览器不会保证一次 start 能一直识别下去,尤其是在移动端,很容易被系统打断。如果不做重启,用户会感觉识别“说停就停”。
几个容易炸的地方
我在做语音识别功能时,踩得比较多的主要是这几类问题。
- 不同浏览器对 SpeechRecognition 的支持和表现差异很大。
- 识别过程往往需要远程服务,网络不通时功能直接不可用。
- 麦克风权限必须在用户授权后才能启动,拒绝或不支持都会导致失败。
- 对专有名词、口音和噪音的容错能力比较弱。
先说兼容性。SpeechRecognition 在 Chrome 里通过 window.SpeechRecognition 或 window.webkitSpeechRecognition 暴露,但它的识别过程并不是纯前端离线完成的,很多实现会把音频送到远端识别服务。这意味着,如果你的页面运行在无法访问对应服务的网络环境下,功能就会直接失效。我遇到的典型场景是:一个面向国内办公网络使用的内部工具,在 Chrome 里调用 SpeechRecognition,结果始终报 network 错误。排查到最后,问题不在代码,而是谷歌识别服务根本无法访问。
第二是麦克风权限。SpeechRecognition 只能在 HTTPS 或 localhost 下工作,并且必须获得用户授权。如果用户拒绝授权或浏览器语音权限被策略禁用,会触发 not-allowed 或 service-not-allowed 错误。生产环境需要对这些错误做提示,而不是让页面静默失败。
第三是识别准确率。SpeechRecognition 对标准普通话、清晰环境下的识别效果还可以,但一旦遇到专有名词、口音或背景噪音,结果就会明显下降。我的建议是:不要把浏览器原生识别用于会议纪要、病历录入这类高准确率场景,它更适合短语音指令,比如搜索关键词、选择菜单或快速输入。
如果你的产品主要面向国内用户,直接使用 SpeechRecognition 要特别谨慎:很多浏览器实际是把语音送到远程服务处理,在国内网络环境下可能根本连不通。至少先做一层网络探测或后端代理,再决定是否作为正式功能。
语音合成:SpeechSynthesis 没那么简单
相比语音识别,SpeechSynthesis 的接入成本更低。一个 SpeechSynthesisUtterance 对象,一个 speak 方法,就能让页面朗读一段文字。但真正把它做成一个好用的功能,还有不少细节。
function speak(text) {
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = 'zh-CN';
utterance.rate = 1;
utterance.pitch = 1;
const voices = speechSynthesis.getVoices();
const preferred = voices.find((voice) => {
return voice.lang === 'zh-CN' && voice.localService;
});
if (preferred) {
utterance.voice = preferred;
}
speechSynthesis.speak(utterance);
}
这段代码比较常规,但生产环境里最容易翻车的是 getVoices() 返回空列表。浏览器加载语音列表是异步的,在你调用 getVoices 时可能还没准备好,尤其是脚本在页面初始化时执行。正确做法是监听 voiceschanged 事件,等语音列表加载完成后再初始化发声逻辑。
另一个容易被忽略的问题是自动播放策略。很多浏览器要求用户必须先与页面发生一次交互,speechSynthesis.speak 才能正常工作。如果你想在页面加载后自动播报,很可能会遇到没有声音的情况。这一点在 Safari 上尤其明显。一个可用的做法是:在用户点击按钮时先调用一次 speechSynthesis.resume() 或播放一个短音频“唤醒”浏览器,之后再响应后续播放。
长文本朗读需要注意什么
长文本是 SpeechSynthesis 的重灾区。有些浏览器在长时间朗读后会出现停止响应、进度丢失或声音变调的问题,一些版本甚至在持续阅读 15 分钟后没有任何回调。如果你做一个“朗读全文”的功能,不要把整篇文章一次性交给 speak,最好先按句或按段落切分,维护一个播放队列,同时提供暂停、继续、停止三个控制。组件销毁时,记得调用 speechSynthesis.cancel(),否则页面切换后下一段语音可能还在播放。
这里还有一个容易误解的地方:speechSynthesis.getVoices() 返回的 voice 列表,不代表这些声音一定适合你的用户。有些 voice 标记为 localService,意味着不需要联网,但中文效果可能不如网络语音。如果你选择了一个远程 voice,用户设备又无法访问对应服务,朗读就会安静地失败。所以要么固定使用本地中文语音,要么在选不到可用 voice 时及时降级,比如用默认语音或者提示用户检查系统语音包。
方案取舍:接 Web Speech API 还是接云服务
讲完两个接口的实战细节,接下来是更实际的决策问题:到底在什么场景下使用 Web Speech API,什么场景下换成云厂商的语音服务?
我把两个方向的典型差异整理成了表格,方便你评估。
| 对比维度 | Web Speech API | 云厂商语音服务 |
|---|---|---|
| 接入成本 | 低,纯前端即可 | 中高,需要后端签名和接口封装 |
| 识别/合成质量 | 一般,受浏览器限制 | 较高,可定制模型和音色 |
| 网络依赖 | 部分实现依赖远程服务 | 必须联网 |
| 离线能力 | 语音合成可能有本地语音,识别基本没有 | 基本不支持 |
| 费用 | 免费 | 按调用量计费 |
| 典型场景 | 原型演示、轻量交互、朗读控件 | 语音客服、会议转写、内容生产 |
从表格可以看出,Web Speech API 最大的优势是“快”。如果只是做一个对准确率要求不高的演示,或者给产品加一个辅助朗读功能,它完全够用。但如果你需要稳定的中文识别、定制热词、声纹识别或者企业级安全保障,云服务是更稳妥的选择。
我的倾向是:把 Web Speech API 作为快速验证方案,把云服务作为正式业务方案。在代码结构上将识别和合成封装成独立模块,内部实现先用 Web Speech API,后续需要替换时再更换适配器,这样既不会拖慢开发,也不会在未来被技术方案绑住。
在真实项目里落地的几条建议
基于前面的实战经验,我总结了几条偏落地层面的建议,不一定适用所有团队,但对大多数前端项目应该有一定参考价值。
- 在开始开发前,先明确功能是否属于“必要路径”。语音交互如果让用户疑惑或者延迟更长,宁可不用。
- 做一个浏览器能力检测模块,统一处理 SpeechRecognition 和 SpeechSynthesis 的兼容性判断,以及当前网络环境是否能访问所需服务。
- 语音识别优先用于“短指令”场景,例如搜索框语音输入、应用内导航;不要尝试整段长文本听写。
- 语音合成要做好播放状态管理,支持暂停、继续、停止、重启,并且页面前进后退时能清理队列。
- 所有调用都要有错误处理。特别是麦克风权限被拒、语音服务不可用、识别超时这几个高频错误,要给出用户能理解的中文提示。
- 如果是组件化开发,在组件卸载时调用 speechSynthesis.cancel(),并移除事件监听,避免跨页面播报和内存泄漏。
这里特别想强调一下第一条。很多团队在引入语音功能时,只看到“能说话”这个亮点,却没有考虑用户是否真的需要。实际上,一个符合直觉的语音交互,必须比手动操作更快、更省事。否则就是给产品增加了一个低频且容易被误触的入口。
我印象很深的是一个物联网管理后台,他们在设备详情页加入了语音播报告警信息,团队没有做队列管理,结果一条设备告警触发了多条播报,声音叠在一起,最后用户反馈体验很差。后来改成每次播报前先 cancel(),并做了按时间戳去重,问题才解决。
最后说几句
Web Speech API 是一个比较典型的“看起来简单,用起来复杂”的浏览器能力。它让我们在前端就能快速实现语音识别与语音合成,但同时也把浏览器的实现差异、网络依赖和用户体验限制摆到了我们面前。
如果你正在做语音功能的技术选型,可以先从原型开始,用 Web Speech API 验证交互流程;如果确认业务需要更强的准确率和可控性,再切换到云服务。整个过程中保持对浏览器兼容性和细节的敬畏,比盲目追求新功能更重要。
希望这篇文章能帮你在做浏览器语音功能时少踩几个坑。如果你在实践中遇到过其他问题,也欢迎自己再深入总结,毕竟语音交互的坑往往只在真实场景里才会暴露。
原创文章,作者:fudengji,如若转载,请注明出处:https://fudengji.cn/article/902/