Javascript 为什么演讲有时不会引发';结束';Chromium浏览器中的事件?

Javascript 为什么演讲有时不会引发';结束';Chromium浏览器中的事件?,javascript,speech-synthesis,Javascript,Speech Synthesis,在Chrome(v72,W10)和Opera中,以下代码片段偶尔会连接到SpeechSynthesistTerrance的端点监听器,可能会运行50次代码片段中的1次。(很抱歉,在这个版本的原始版本中,它可以更容易地被复制——现在,创建按钮点击的声音看起来让这个bug更加罕见) button.onclick=()=>{ log('start script'); button.disabled=true; const-utt=新的语音合成('e'); utt.addEventListener('

在Chrome(v72,W10)和Opera中,以下代码片段偶尔会连接到
SpeechSynthesistTerrance
端点
监听器,可能会运行50次代码片段中的1次。(很抱歉,在这个版本的原始版本中,它可以更容易地被复制——现在,创建按钮点击的声音看起来让这个bug更加罕见)

button.onclick=()=>{
log('start script');
button.disabled=true;
const-utt=新的语音合成('e');
utt.addEventListener('end',()=>{
console.log(“已触发的结束事件”);
});
//只是为了调试的完整性,似乎没有抛出任何错误
utt.addEventListener('error',(err)=>{
console.log('err',err)
});
演讲综合(utt);
设置超时(()=>{
console.log('finished?');
}, 1500);
};
点击
编辑/更新:@Ouroborus指出,这确实是一个


我兴奋起来,开始尝试复制这个。当问题发生时,我始终看到gc活动发生在“开始脚本”和“完成”日志之间

成功的例子:

失败的例子:

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

为了进一步测试这一理论,我用
--js flags=“--expose gc”
标志启动了chrome,该标志启用了v8gc函数,允许强制垃圾收集

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

似乎您可以通过
控制台对
SpeechSynthesistTerrance
对象进行gc'd。记录它。这似乎确实导致了活动的一致交付。显然,如果要创建大量这些对象,防止它们的收集可能并不理想:

button.onclick=()=>{
log('start script');
button.disabled=true;
const-utt=新的语音合成('e');
//防止utt对象的垃圾收集
控制台日志(utt);
utt.addEventListener('end',()=>{
console.log(“已触发的结束事件”);
});
//只是为了调试的完整性,似乎没有抛出任何错误
utt.addEventListener('error',(err)=>{
console.log('err',err)
});
演讲综合(utt);
设置超时(()=>{
console.log('finished?');
}, 1500);
};

点击
Oops!看起来Opera还没有实现自动播放限制,我的Chrome上有一个允许自动播放的自定义设置,所以我没有看到错误。点击仍然触发话语,但不幸的是,它的再现性要差得多。您不是使用了“onend”而不是“utt.addEventListener('end',()=>{”@UdaraKasun不,我总是使用
addEventListener
作为
end
事件,你可以看到编辑历史,但我尝试过,它看起来像是使用
。onend=
的行为是一样的。能够在Chrome 72.0.3626.81中复制。可能20分之一左右,并且在开发控制台打开时似乎不会发生。@Kaido在Mojave,c上复制hrome v 72.0.3626.121解决方法与您建议的类似:将
SpeechSynthesistTerrance
对象存储在更永久的位置,以便不会被收集。