为何Web Speech API的voiceschanged事件会在Chrome页面加载时触发?
Chrome中
voiceschanged页面加载时自动触发的核心成因 这个行为完全符合MDN记载的事件触发规则,不存在无依据的特殊逻辑,容易让人困惑的本质原因是多数人忽略了语音列表从"空初始状态"到"有效列表"的转变,本身就是一次满足触发条件的变更。
- 首先,Chrome对Web Speech模块的语音列表采用了异步初始化逻辑:页面脚本刚执行时,
speechSynthesis实例的内部语音缓存是空数组,此时立刻调用speechSynthesis.getVoices(),拿到的永远是空值。浏览器会在后台异步拉取系统预装语音、扩展安装的在线语音包资源,等所有资源挂载完成后,才会把有效语音条目填充到这个内部缓存里。 - 按照事件的定义规则,只要
getVoices()的返回值从一个状态变成另一个状态,就需要抛出voiceschanged事件。空的初始缓存到填充完成的有效列表,是非常明确的列表内容变更,自然会在填充完成的瞬间触发一次事件——这就是你观察到的"页面加载时自动触发"的来源,不是Chrome额外加的特殊触发分支。 - 之前广为流传的"需要手动补一次
getVoices()调用"的写法,是适配老版本Chrome的兜底方案:在Chrome早期版本里,语音列表的初始化时机早于页面脚本执行的时机,如果你在脚本里注册监听器的时候,首次语音列表已经填充完成,那这次初始的变更事件早就发完了,监听器根本收不到回调,只能手动调用一次方法拿列表。 - 不同浏览器的初始化时序差异,也是MDN没有单独提及这个现象的原因:比如Firefox会在创建
speechSynthesis实例的时候就同步完成语音列表填充,脚本刚拿到实例时getVoices()就已经返回有效列表,自然不会触发那次初始的变更事件。MDN作为跨浏览器的通用规范说明,不会特意把单浏览器的异步初始化行为写到通用规则里。
顺带提一句,你现在写的
getVoices()逻辑有个小坑:如果后面遇到系统新装语音包、触发第二次voiceschanged事件的情况,代码会在下拉选择框里堆一堆重复的选项,最好在循环创建option之前,先把下拉框里的旧option清掉,省得后续出冗余列表。
内容的提问来源于stack exchange,提问作者nCardot
相关产品推荐
相关产品推荐

