alienboy
alienboy

Reputation: 443

Synchronous execution in javascript with speechSynthesis.speak()

Currently, I am trying to have the browser speak an array of strings sequentially, but that is not being done sequentially; the first string is read and then the last string is read. How can I modify my code so each string is read sequentially?

async function wrapper(){
  var text = "sen ten ce one. sen ten ce two. sen ten ce three.";
  var result = text.match( /[^\.!\?]+[\.!\?]+/g );
  var ssu = new SpeechSynthesisUtterance();
  for(var i = 0; i<result.length; i++){
    sentence = result[i];
    ssu.text = sentence;
    await window.speechSynthesis.speak(ssu);
  }
wrapper();

If I write the sentences to the console, they are printed before the sentence has been spoken.

Upvotes: 1

Views: 1999

Answers (3)

ytyng
ytyng

Reputation: 715

You can return new Promise in async function.

How about this:

function asyncSpeak(text) {
  const ssu = new SpeechSynthesisUtterance()
  ssu.text = text
  ssu.lang = 'en-US'
  speechSynthesis.speak(ssu)
  return new Promise((resolve, reject) => {
    ssu.onend = () => {
      resolve()
    }
  })
}

async function wrapper() {
  await asyncSpeak('one two three four five six seven eight nine ten')

  const text = 'sen ten ce one. sen ten ce two. sen ten ce three.'
  const words = text.match(/[^\.!\?]+[\.!\?]+/g)
  for(const word of words) {
    await asyncSpeak(word)
  }
}

wrapper()

Upvotes: 1

Lennholm
Lennholm

Reputation: 7480

You can't use await with speechSynthesis.speak() because it doesn't return a promise. You can solve this by using the onend event and wrap it in a Promise:

async function wrapper(){
  var text = "sen ten ce one. sen ten ce two. sen ten ce three.";
  var result = text.match( /[^\.!\?]+[\.!\?]+/g );
  var ssu = new SpeechSynthesisUtterance();
  for(var i = 0; i<result.length; i++){
    sentence = result[i];
    ssu.text = sentence;
    await new Promise(function(resolve) {
      ssu.onend = resolve;
      window.speechSynthesis.speak(ssu);
    });
  }
wrapper();

Upvotes: 2

mahesh shah
mahesh shah

Reputation: 68

async await only works with promises. speachSynthesis.speak doesn't return a promise so it will not wait till the completion of speak. So it is better if you use onend callback.

Check below code

var ssu = new SpeechSynthesisUtterance();

function wrapper(){
  var text = "sen ten ce one. sen ten ce two. sen ten ce three. sen ten ce four.";
  var result = text.match( /[^\.!\?]+[\.!\?]+/g );

  speak(result, 0);
}

function speak(result, index) {
    if(index >= result.length)
        return;

    var sentence = result[index];
    ssu.text = sentence;
    ssu.onend = function() {
        speak(result, ++index);
    };
    window.speechSynthesis.speak(ssu);
}

wrapper()

Upvotes: 2

Related Questions