Почему SpeechSynthesisUtterance иногда не запускает событие end в браузерах на основе Chromium? - программирование

Почему SpeechSynthesisUtterance иногда не запускает событие end в браузерах на основе Chromium?

Как в Chrome (v72, W10), так и в Opera следующий фрагмент очень редко запускает присоединенный end прослушиватель SpeechSynthesisUtterance, возможно, 1 из 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);
};
<button id="button">click</button>
4b9b3361

Ответ 1

Редактировать/Обновить: @Ouroborus указал, что это действительно открытая ошибка Chromium


Я запустил Sawbuck и начал попытки воспроизвести это. Когда возникает проблема, я постоянно вижу, как между "start script" и "done" происходит действие gc. журналы.

Пример успеха:

enter image description here

Пример сбоя:

enter image description here

Таким образом, может показаться, что процесс gc мешает доставке end события.

Для дальнейшего тестирования этой теории я запустил chrome с --js-flags="--expose-gc" который включает функцию v8 gc, позволяющую принудительно собирать мусор.

Если я window.gc() ваш тестовый код и добавлю window.gc() перед console.log('start script'), я больше не смогу воспроизвести проблему (> 50 попыток). Возможно, это потому, что это уменьшает/исключает вероятность того, что gc произойдет во время речевого высказывания.

Похоже, что вы можете запретить SpeechSynthesisUtterance объект SpeechSynthesisUtterance от console.log -ing it. Это, кажется, приводит к последовательной доставке события. Очевидно, что предотвращение их коллекции, вероятно, не идеально, если вы создаете большое количество этих объектов:

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>