Sno*_*now 19 javascript speech-synthesis
在Chrome浏览器(v72,W10)和Opera中,以下代码段有时 似乎都不会运行附加的end侦听器到SpeechSynthesisUtterance,可能运行了该代码段的50倍。(很抱歉,在此版本的原始版本中,可以更轻松地复制它-现在,创建按钮单击时的发音看起来使该错误更加罕见)
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);
};Run Code Online (Sandbox Code Playgroud)
<button id="button">click</button>Run Code Online (Sandbox Code Playgroud)
从我所看到的情况来看,如果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');Run Code Online (Sandbox Code Playgroud)
据我所知,Firefox(56)并没有出现此问题-在其中,end侦听器始终可以正常触发。
我是否以某种方式不能正确地正确连接侦听器,或者这是Chromium错误?
编辑/更新:@Ouroborus指出这确实是一个开放的Chromium错误
我解雇了Sawbuck并开始尝试重现此内容。发生问题时,我始终看到在“开始脚本”和“完成?”之间发生gc活动。日志。
成功的例子:
失败示例:
因此,似乎gc进程正在干扰end正在传递的事件。
为了进一步验证这一理论,我从--js-flags="--expose-gc"启用v8 gc功能的标志开始chrome ,从而允许强制垃圾回收。
如果我修改您的测试代码并在window.gc()之前添加console.log('start script'),那么我将无法重现该问题(尝试次数大于50)。这可能是因为它减少/消除了语音发声期间出现gc的机会。
看来您可以SpeechSynthesisUtterance通过console.log-ing 对象来防止该对象被gc 损坏。这似乎确实导致事件的一致交付。如果要创建大量这些对象,显然阻止它们的收集可能不是理想的选择:
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);
};Run Code Online (Sandbox Code Playgroud)
<button id="button">click</button>Run Code Online (Sandbox Code Playgroud)