How to wait until speech is finished inside Loop?

For SpeechSynthesisUtterance API there is an onend event what you can play with (SpeechSynthesisUtterance: end event).

So I guess you can add an event listener to onend where you need to call the next iteration's code. One good technique is to use Promise in asynchronous cases to wait until a callback finishes. I have created a working example for the above case from your question:

(function() {
  play();

  async function play() {
    let all = "Oak is strong and also gives shade \n \
              Cats and dogs each hate the other \n \
              The pipe began to rust while new \n Bye.";

    sentences = all.split('\n');

    for (i = 0; i < sentences.length; i++) {
      await getNextAudio(sentences[i]);
    }

    async function getNextAudio(sentence) {
      console.log(sentence);
      let audio = new SpeechSynthesisUtterance(sentence);
      window.speechSynthesis.speak(audio);

      return new Promise(resolve => {
        audio.onend = resolve;
      });
    } 
  }
})();

If you are interested in more details, please go for the following links to read further:

  1. Promise
  2. SpeechSynthesis.speak()
  3. SpeechSynthesisUtterance.onend
  4. async function

The solution works just like charm, hope this helps!


There's also an onstart event which you could use like this:

for (i = 0; i < sentences.length; i++) {
  const sentence = sentences[i];
  const audio = new SpeechSynthesisUtterance(sentence);
  audio.onstart = () => console.log(audio.text);
  speechSynthesis.speak(audio);
}

Or slightly shorter:

for (const sentence of sentences) {
  const audio = new SpeechSynthesisUtterance(sentence);
  audio.onstart = () => console.log(audio.text);
  speechSynthesis.speak(audio);
}

PS you could amend the top of your code to use const (or let) instead of var like this:

const all = "Oak is strong and also gives shade \n \
    Cats and dogs each hate the other \n \
    The pipe began to rust while new \n Bye.";
const sentences = all.split('\n');