当前位置: 代码迷 >> JavaScript >> 为什么SpeechSynthesisUtterance有时不会在基于Chromium的浏览器中触发“结束”事件?
  详细解决方案

为什么SpeechSynthesisUtterance有时不会在基于Chromium的浏览器中触发“结束”事件?

热度:11   发布时间:2023-06-05 14:06:30.0

在Chrome(v72,W10)和Opera中,以下代码段偶尔 附加的end侦听器到SpeechSynthesisUtterance ,可能是运行代码段50次中的1次。 (对不起,在这个版本的原始版本中,它可以更容易地复制 - 现在,创建按钮点击的话语看起来让错误变得更加罕见)

 button.onclick = () => { console.log('start script'); button.disabled = true; const utt = new SpeechSynthesisUtterance('e'); utt.addEventListener('end', () => { console.log('end event triggered'); }); // just for debugging completeness, no errors seem to be thrown though utt.addEventListener('error', (err) => { console.log('err', err) }); speechSynthesis.speak(utt); setTimeout(() => { console.log('finished?'); }, 1500); }; 
 <button id="button">click</button> 

从我所看到的,如果end事件激活,它将始终在给定的页面加载中激活,这就是我禁用上述代码段中的按钮的原因。 (你必须多次重新运行该片段以查看问题)

如果您在Chrome中运行以下代码段(W10上为72)且禁用了自动播放限制,则可以更轻松地重现它。 (转到chrome://flags/ ,将自动播放策略更改为无需用户手势 )。

(在Opera中,不幸的是,在第一个片段中似乎很难再现)

 console.log('start script'); function say(text) { const utt = new SpeechSynthesisUtterance(text); utt.addEventListener('end', () => console.log('end: ' + text)); // just for debugging completeness, no errors seem to be thrown though utt.addEventListener('error', (err) => { console.log('err on ' + text + ', ', err) }); speechSynthesis.speak(utt); } say('foo'); say('bar'); 

就我所见,Firefox(56)没有这个问题 - 在其中, end监听器总是正常激活。

我是不是在某种程度上没有正确地附加听众,或者这是一个Chromium bug?

编辑/更新 :@Ouroborus指出这确实是一个


我解雇了并开始尝试重现这一点。 当问题发生时,我一直看到在'开始脚本'和'完成'之间发生了gc活动? 日志。

成功案例:

失败的例子:

因此,似乎gc进程可能会干扰正在传递的end事件。

为了进一步测试这个理论,我用--js-flags="--expose-gc"标志启动了chrome,它启用了v8 gc函数,允许强制垃圾收集。

如果我修改你的测试代码并在console.log('start script') window.gc()之前添加window.gc() ,我将无法再重现该问题(> 50次尝试)。 这可能是因为它减少/消除了语音发声过程中gc发生的可能性。

看来你的SpeechSynthesisUtterance对象由被gc'd console.log -ing它。 这似乎确实导致事件的一致传递。 如果您正在创建大量这些对象,显然阻止它们的收集可能并不理想:

 button.onclick = () => { console.log('start script'); button.disabled = true; const utt = new SpeechSynthesisUtterance('e'); // Prevent garbage collection of utt object console.log(utt); utt.addEventListener('end', () => { console.log('end event triggered'); }); // just for debugging completeness, no errors seem to be thrown though utt.addEventListener('error', (err) => { console.log('err', err) }); speechSynthesis.speak(utt); setTimeout(() => { console.log('finished?'); }, 1500); }; 
 <button id="button">click</button>