DEV Community

Cover image for Simplify code by promisifying `setTimeout`
PuruVJ
PuruVJ

Posted on • Originally published at puruvj.dev

Simplify code by promisifying `setTimeout`

Originally Published @ puruvj.dev

Recently, when I was working on my practice project Microsoft Todo Clone, I needed to implement code like this:

#1 Do Task 1
#2 Wait for 200ms
#3 Do task 2
#4 Wait for 200ms
#5 Do Task 3
Enter fullscreen mode Exit fullscreen mode

Notice #2 and #4. They smell of setTimeout😖. setTimeout takes in a callback, meaning there will be an indentation. Whenever those appear, means the code's gonna get ugly.

So I wrote this code in JS

doTask1();

setTimeout(() => {
  doTask2();

  setTimeout(() => {
    doTask3();
  }, 200);
}, 200);
Enter fullscreen mode Exit fullscreen mode

Now you can see for yourself, this code SMELLS. BAD.

The moment I wrote it, I knew it wouldn't work in long-term. What if I needed to an extra step of waiting and doing a Task #4? Or rearranging the order.

So, I declared a utility function and it solved the problem completely.

/**
 * @param {number} time Time to wait for in milliseconds
 */
function waitFor(time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}
Enter fullscreen mode Exit fullscreen mode

Here we're returning a Promise, which resolves when the setTimeout function inside runs.

It's usage would be as simple as

await waitFor(200);
Enter fullscreen mode Exit fullscreen mode

So the spaghetti code above could be rearranged like this:

doTask1();

await waitFor(200);

doTask2();

await waitFor(200);

doTask3();
Enter fullscreen mode Exit fullscreen mode

See how simple it became? It reads exactly like the text version I wrote at the top. It's very idiomatic 😎.

Shorter code

That code snippet could be simplified further

const waitFor = (time) => new Promise((resolve) => setTimeout(resolve, time));
Enter fullscreen mode Exit fullscreen mode

Discussion (7)

Collapse
darkwiiplayer profile image
DarkWiiPlayer

I'd use the chance to change the time argument to use seconds because who the fuck thought milliseconds were acceptable?

Collapse
puruvj profile image
PuruVJ Author

You can sure change it. What Mark suggested would work.

However, I disagree with your point. I've used more timers less than 1 second or timeouts like 1.5 seconds that I kinda find the milliseconds method better. Plus its so standard thanks to langs like Java and C and our own JS that any API respecting seconds would feel plain weird

Collapse
darkwiiplayer profile image
DarkWiiPlayer

I've used more timers less than 1 second or timeouts like 1.5 seconds

What's the problem with sleep(1.5)? I still find that more natural than sleep(1500)

Plus its so standard

No it's not. C uses seconds, the linux command-line program sleep also uses seconds... There's lots of examples out there and milliseconds is far from common.

The only two differences are:

  1. Seconds are the SI base unit.
  2. Seconds are within the orders of magnitude that humans can perceive.

I'd say both of those are clearly benefits of using seconds.

Thread Thread
puruvj profile image
PuruVJ Author

Well, you have a point.

However having seconds measurement in a language that puts milliseconds as first class citizens would incur the cost of context switching.

Thanks for the info

Thread Thread
darkwiiplayer profile image
DarkWiiPlayer

The context switching is precisely why I want this. If you're dealing with seconds in the backend but have to constantly switch to thinking in milliseconds for the frontend code, that's mental work I could spend thinking about the actual code.

Collapse
markwitt_me profile image
Mark Witt

Change setTimeout(resolve, time) to setTimeout(resolve, time * 1000)

Collapse
darkwiiplayer profile image
DarkWiiPlayer

Yes, thanks but I was already well aware of how to convert milliseconds to seconds ;D