I'm displaying an animated graphic whilst SpeechSynthesisUtterance is speaking. I'm using the onend property to detect when speaking has finished to remove the animated graphic. However there is a significant delay between the speaking finishing and the onend event firing, which means the animated graphic carries on playing for approximately 1 second even though the speaking has finished. Is it possible to remove this delay? The below code is a simple demonstration of the problem.
let utterance = new SpeechSynthesisUtterance("Approximately a second delay after utterance has finished and the onend event firing");
speechSynthesis.speak(utterance);
utterance.onend = function () {
console.log("There is a delay before this message appears?");
}
Rather than using the end
event, here is an example of how you can use the boundary
event to remove something from the DOM based on the evt.charIndex
of the utterance being spoken.
This removes the graphic after the penultimate word finishes speaking:
function getPenultimateWordEndingIndex(text) {
const words = text.split(' ').filter(Boolean)
// Can use words.slice(-1, -1)[0] for better browser support
return text.lastIndexOf(words.at(-1))
}
const text = 'This image should be removed after hearing the word "event" spoken.'
const index = getPenultimateWordEndingIndex(text)
const graphic = document.getElementById('graphic')
const utter = new SpeechSynthesisUtterance(text)
utter.addEventListener('boundary', evt => {
if (evt.charIndex >= index) {
graphic.remove()
}
})
document.getElementById('speak').addEventListener('click', () => {
window.speechSynthesis.speak(utter)
})
<img src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" width="100" id="graphic" />
<p>This image should be removed after hearing the word "event" spoken. (accept chrome/android which doesn't fire boundary events)</p>
<button id="speak">speak</button>