SpeechRecognition需兼容检测:const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;lang必须显式设为'zh-CN';start()须由用户手势触发且仅限HTTPS/localhost。

SpeechRecognition 构造函数必须用特性检测获取
硬写 new SpeechRecognition() 在 Chrome 里会直接报 ReferenceError,因为 Chrome/Edge 只暴露 webkitSpeechRecognition,Firefox 部分版本才支持无前缀的 SpeechRecognition(且需手动开启 media.webspeech.recognition.enable),Safari 完全不支持。
正确做法是先做兼容性判断:
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
再检查是否可用:
if (!SpeechRecognition) {<br> console.error('当前浏览器不支持语音识别');<br> // 降级为文本输入或隐藏语音按钮<br>}
- 不能依赖
typeof SpeechRecognition !== 'undefined',某些旧版 Firefox 返回function但实际不可用 - Firefox 用户需在地址栏输入
about:config,搜索并启用media.webspeech.recognition.enable - Safari 无替代方案,必须提供纯文本 fallback
lang 必须显式设为 'zh-CN' 才能识别中文
哪怕用户系统语言是中文,recognition.lang 默认仍是 'en-US'。设成 'zh'、'cn' 或空字符串都会退回到英文模型,中文识别率暴跌到 30% 以下。
立即学习“前端免费学习笔记(深入)”;
初始化后立即设置:
const recognition = new SpeechRecognition();<br>recognition.lang = 'zh-CN';
-
'zh-CN'区分大小写和短横,'zh_cn'或'ZH-CN'均无效 - 若需多语言切换,每次调用
start()前都应重置lang,否则沿用上次值 - 部分 Android Chrome 对
'zh-TW'支持更好,但大陆用户建议坚持用'zh-CN'
start() 必须由用户手势触发且运行于 HTTPS/localhost
在控制台执行 recognition.start()、页面加载时自动调用、或定时器触发,浏览器都会静默拒绝——既不弹权限框,也不抛错,onend 立即触发,onerror 完全不触发。
唯一可靠方式是绑定用户点击事件:
document.getElementById('btn').addEventListener('click', () => {<br> recognition.start();<br>});
- HTTP 域名(非 localhost)下
start()直接失败,onerror中event.error是'not-allowed' - 用户点“禁止”后,后续所有
start()都进onend,需靠状态标记 + 提示语引导用户去浏览器设置里手动开启麦克风 - 移动端 Safari 不支持,但 iOS Chrome 实际走的是系统级语音识别,仍需 HTTPS
onresult 中只取 isFinal === true 的结果
event.results 是只读的 SpeechRecognitionResultList,不是数组;每项是 SpeechRecognitionResult,本身也是类数组。中间结果(isFinal: false)会多次触发,最终结果(isFinal: true)才稳定。
提取逻辑必须过滤 final 结果:
recognition.onresult = (event) => {<br> const finalTranscript = Array.from(event.results)<br> .filter(r => r.isFinal)<br> .map(r => r[0].transcript)<br> .join('');<br> console.log(finalTranscript);<br>};
- 别用
event.results[0][0].transcript直接取,它可能是 interim 结果 -
interimResults: true时,onresult触发频率高,但只有isFinal === true的项才该插入编辑器或存库 - 如果用了
continuous: true,event.results可能包含多个isFinal: true的块,需全部处理
lang 没设对、start() 没绑用户点击。这三处任一出错,整个流程就静默失效,连错误提示都没有。



















