Why does a SpeechSynthesisUtterance sometimes not fire an 'end' event in Chromium-based browsers?

帅比萌擦擦* 提交于 2019-12-04 16:54:51

问题


In both Chrome (v72, W10) and Opera, the following snippet very occasionally does not seem to run the attached end listener to the SpeechSynthesisUtterance, maybe 1 out of 50 times the snippet is run. (Sorry, in the original version of this, it could be reproduced much more easily - now, creating the utterance on button click looks to have made the bug much more rare)

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>

From what I've seen, if the end event ever activates, it will always activate within a given pageload, which is why I disable the button in the above snippet. (you'll have to rerun the snippet many times to see the problem)

You can reproduce it more readily if you run the below snippet in Chrome (72 on W10) with autoplay restrictions disabled. (go to chrome://flags/, change Autoplay policy to No user gesture is required).

(In Opera, it seems to be similarly difficult to reproduce as in the first snippet, unfortunately)

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) does not have this issue as far as I can see - in it, the end listener always fires properly.

Am I somehow not attaching the listener sufficiently properly, or is this a Chromium bug?


回答1:


Edit/Update: @Ouroborus pointed out that this is indeed an open Chromium bug


I fired up Sawbuck and started attempts to reproduce this. When the issue occurs, I consistently see gc activity happening between the 'start script' and 'finished?' logs.

Example of success:

Example of failure:

So, it seems like it may be that the gc process is interfering with the end event being delivered.

To further test this theory I started chrome with the --js-flags="--expose-gc" flag which enables the v8 gc function, allowing one to force garbage collection.

If I modify your test code and add window.gc() before console.log('start script'), I can no longer reproduce the issue (>50 attempts). It's possible this is because it reduces/eliminates the chance that gc occurs during the speech utterance.

It seems that you may be able to prevent the SpeechSynthesisUtterance object from being gc'd by console.log-ing it. This does seem to result in consistent delivery of the event. Obviously preventing their collection is probably not ideal if you're creating a great number of these objects:

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>


来源:https://stackoverflow.com/questions/54861046/why-does-a-speechsynthesisutterance-sometimes-not-fire-an-end-event-in-chromiu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!