loading words...

Jun 11, 2019 23:57:32

javascript promises quicktip

by @swizecteller | 255 words | 3🔥 | 116💌

Swizec Teller

Current day streak: 3🔥
Total posts: 116💌
Total words: 32303 (129 pages 📄)

Here's a fun JavaScript quick tip about promises

What do you think this code prints?

const sleep = () =>

new Promise(resolve => setTimeout(resolve, Math.random() * 100));

[1, 2, 3, 4].forEach(async i => {

  await sleep();

  console.log("wrong", i);

});

---

You've got a sleep() function that returns a Promise and resolves it after a random timeout of a few hundred milliseconds.

You iterate through 1,2,3,4, wait for sleep(), and print the number.

What do you get?

---

If you guessed 1,2,3,4 listen up. If not, 👏 you are smarter than me. I knew something was fishy but had to try it to make sure.

The output is jumbled. Random even

---

Here's what happens.

forEach is sequential and it _does_ run the code in correct order. First for 1, then for 2, etc.

The method inside forEach is async and it _does_ wait for sleep() to finish before printing. That's what await is for 👉 waiting until promises resolve.

---

BUT forEach itself is not async, which means that while the functions _start_ in sequence, the waiting happens _in parallel_

Also code after forEach starts executing before sleeps are done.

<mind blown gif>

---

You need a good old fashioned loop to get wait for each sleep and print in sequence. Like this

async function bla() {

  for (let i of [1, 2, 3, 4]) {

    await sleep();

    console.log("right", i);

  }

}

bla();

---

If it's okay for sleeps to happen in parallel, and the output to be jumbled, but you need to make sure it's all done before you continue, then Promise.all is your friend

await Promise.all([1,2,3,4].map(async i => {

  await sleep();

  console.log(i)

  return;

})

contact: email - twitter / Terms / Privacy