Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to wait until lines are printed iteratively?

I am building a terminal like personal website and I want to display a welcome banner + message after one another. I have this cool effect where individual lines appear from top to bottom and characters from left to right (See here for yourself).

My problem is that the welcome banner and the welcome message are mixed up with one another. Thus, I want to wait until the banner is printed before printing the message. However something about my code must be wrong… (I tried using await/async) …

Here you have a small reproducible example of the issue. All lines with the character "a" should be printed before lines with character "b". Can you please point out what the root of the problem is?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

banner = ["aaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaa"]
welcomeMsg = ["bbbbbbbbbbbb", "bbbbbbbbbbbb", "bbbbbbbbbbbb", "bbbbbbbbbbbb"]
var before = document.getElementById("before");


setTimeout(async function() {
  await loopLines(banner, "", 80);
  loopLines(welcomeMsg, "", 80);
}, 100);

async function addLine(text, style, time) {
  var t = "";
  for (let i = 0; i < text.length; i++) {
    if (text.charAt(i) == " " && text.charAt(i + 1) == " ") {
      t += "&nbsp;&nbsp;";
      i++;
    } else {
      t += text.charAt(i);
    }
  }
  setTimeout(function() {
    var next = document.createElement("p");
    next.innerHTML = t;
    next.className = style;

    before.parentNode.insertBefore(next, before);

    window.scrollTo(0, document.body.offsetHeight);
  }, time);
  return;
}

async function loopLines(name, style, time) {
  for (var i = 0; i < name.length; i++) {
    await addLine(name[i], style, i * time);
  }
  return;
}
p {
  display: block;
  line-height: 1.3em;
  margin: 0;
  overflow: hidden;
  /* white-space: nowrap; */
  margin: 0;
  letter-spacing: 0.05em;
  animation: typing 0.5s steps(30, end);
  /* font-size: calc(2vw + 7px); */
  font-size: min(20px, calc(1.5vw + 7px));
}
@keyframes typing {
  from {
    width: 0;
  }
  to {
    width: 100%;
  }
}
<a id="before"></a>

>Solution :

In addLine you don’t use await. Instead you call setTimeout, but that doesn’t return a pending promise. So the promise returned by addLine resolves immediately without waiting for the timeout to complete.

To change that, make use of a promisified version of setTimeout. I have added its definition at the top of the snippet. Then see where addLine uses it instead of setTimeout:

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

banner = ["aaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaa"]
welcomeMsg = ["bbbbbbbbbbbb", "bbbbbbbbbbbb", "bbbbbbbbbbbb", "bbbbbbbbbbbb"]
var before = document.getElementById("before");


setTimeout(async function() {
  await loopLines(banner, "", 80);
  loopLines(welcomeMsg, "", 80);
}, 100);

async function addLine(text, style, time) {
  var t = "";
  for (let i = 0; i < text.length; i++) {
    if (text.charAt(i) == " " && text.charAt(i + 1) == " ") {
      t += "&nbsp;&nbsp;";
      i++;
    } else {
      t += text.charAt(i);
    }
  }
  await delay(time);  // <---------------
  var next = document.createElement("p");
  next.innerHTML = t;
  next.className = style;
  before.parentNode.insertBefore(next, before);
  window.scrollTo(0, document.body.offsetHeight);
}

async function loopLines(name, style, time) {
  for (var i = 0; i < name.length; i++) {
    await addLine(name[i], style, i * time);
  }
}
p {
  display: block;
  line-height: 1.3em;
  margin: 0;
  overflow: hidden;
  /* white-space: nowrap; */
  margin: 0;
  letter-spacing: 0.05em;
  animation: typing 0.5s steps(30, end);
  /* font-size: calc(2vw + 7px); */
  font-size: min(20px, calc(1.5vw + 7px));
}
@keyframes typing {
  from {
    width: 0;
  }
  to {
    width: 100%;
  }
}
<a id="before"></a>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading