How to wait for a function, which calls itself recursively with setTimeout, to complete?

Tags: , , ,



I am new to Javascript and currently working on a website, that changes how it looks by itself over time.

One part of this page is a “Typewriter”, that writes out a text letter by letter. This is the code for this Typewriter:

function typeWriter(element, txt) {
    if (txt.length > 1) {
        element.textContent += txt.charAt(0);
        var newText = txt.slice(1,txt.length);
        setTimeout(typeWriter, 150 , element, newText);
    } else {
        element.textContent += txt.charAt(0);
    }
}

Now I want to wait for the typewriter-function to finish with its text before doing another change to let’s say my background-color.

function runThis(){
    var line1 = document.getElementById("line1");
    typeWriter(line1, "This should be written first, before continuing");
    document.body.style.backgroundColor = "blue";
}

To my understanding, the setTimeout makes my typewriter async, so if I do it as in the example above the third line of code will run as soon as the typewriter hits the first setTimeout.

I tried to realize this with the async/await terms and promises. But even after I resolve the promise, my “runThis” function won’t continue after the typewriter finishes.

function typeWriter(element, txt) {
    return new Promise (function(resolve,reject) {
        if (txt.length > 1) {
            element.textContent += txt.charAt(0);
            var newText = txt.slice(1,txt.length);
            setTimeout(typeWriter, 150, element, newText);
        } else {
            element.textContent += txt.charAt(0);
            resolve();
        }
    })
}


async function runThis() {
    var line1 = document.getElementById("line1");
    await typeWriter(line1, "papupa");
    console.log("waiting over")
    document.body.style.backgroundColor = "blue";
}

Can you please help me figure out what’s wrong here? Thank you very much

Answer

You can wrap the setTimeout in a promise. This will allow you to use the async/await syntax to express the intention of your code more clearly, almost as if it was running synchronously.

async function runThis() {
  var line1 = document.getElementById("line1");
  await typeWriter(line1, "papupa");
  document.body.style.backgroundColor = "blue";
}

async function typeWriter(element, txt) {
  for (var i = 0; i < txt.length; i++) {
    element.textContent += txt[i]; // this is shorthand for txt.charAt(i)
    await pause();
  }
}

function pause() {
  return new Promise(function(resolve, reject) {
    setTimeout(resolve, 150);
  });
}



Source: stackoverflow