setTimeout is a callback-style function. What would happen if we change that?
Tags: programming, functional, javascript, mojiscript
Published: 2018-10-08 16:39:23

---
title: setTimeout is a callback-style function. What would happen if we change that?
published: true
description: 
tags: programming, functional, javascript, mojiscript
---

[![Clock gold timepiece](https://thepracticaldev.s3.amazonaws.com/i/3jsp2u3jj0se7mh9fv4i.jpg)](https://unsplash.com/photos/Ai7sV3SSMIQ)

Today it is common practice to transform node-style-callback functions into promise-style functions. So why haven't we done this for `setTimeout`?

The main reason to prefer a promise-style function over a node-style-callback is to avoid [Callback Hell](http://callbackhell.com/).

![Ryo fireballing code in callback hell](https://thepracticaldev.s3.amazonaws.com/i/a79vj0fvvdylajtcqz87.gif)

Nobody wants to see that.

After looking at `setTimeout` (and it's siblings `setInterval` or `setImmediate`), I can clearly see that it's a callback-style function.

```javascript
setTimeout(callback, 1000);
//         --------
//                 \
//                   See that? Right there. A callback!
```

Yet, it's so incredibly rare to see anyone convert `setTimeout` from callback to a promise. How has `setTimeout` flown under the radar? Is `setTimeout` different enough to get a pass?

I say no.

# Node-style-callback functions

`setTimeout` may have been passed over because even though It's clearly a callback-style function, it is not a node-style-callback function, which is a little different.

First, let's have a look at node-style-callbacks to better see the difference. `fs.readFile` is a great example of a node-style-callback function.

```javascript
fs.readFile(path[, options], callback)
//                           --------
//                          /
//    callback must be last
```

And the callback itself must look like this:

```javascript
const callback = (err, data) => { /* ... */ }
//                ---  ----
//               /          \
//    error first             data last
```

If `setTimeout` was a traditional node-style-callback function, it could be easily converted with node's `util.promisify`. Here's an example of how easy it is to use `util.promisify` to convert `fs.readFile` into a promise-style function.

```javascript
import fs from 'fs'
import { promisify } from 'util'

const readFile = promisify(fs.readFile)
```

Unfortunately, `util.promisify` will not work. First, because the callback is not the last argument. Second, because the callback does not follow the `(err, data)` interface.

# Promisifying setTimeout

Fortunately, transforming this manually is just as simple. I'll call the new function `sleep`.

```javascript
const sleep = milliseconds => value => new Promise (resolve =>
  setTimeout(() => resolve(value), milliseconds)
)
```

A few key things I would like to point out, regarding this code.

* `sleep` is curried. You'll see why later.
* `sleep` takes a `value` and then resolves the `value`. Again, you'll see why later.

# Using sleep

Adding a pause into your code is now as simple as using a promise.

```javascript
const log => msg => console.log(msg)

sleep(1000)('Hello World').then(log)
```

That's fine, but not the reason why I am writing this.

What really excites me about `sleep` is the ability to slip it into the middle of promise chains.

In this example, it was trivial to add a 1 second delay between API calls.

```javascript
import axios from 'axios'
import sleep from 'mojiscript/threading/sleep'

const fetchJson = url => axios.get(url).then(response => response.data)
const log = msg => (console.log(msg), msg)
//                                  -
//                                 /
//     comma operator. google it.

fetchJson('https://swapi.co/api/people/1')
  .then(log)
  .then(sleep(1000))
  .then(() => fetchJson('https://swapi.co/api/people/2'))
  .then(log)
  .then(sleep(1000))
  .then(() => fetchJson('https://swapi.co/api/people/3'))
  .then(log)
```

Because `sleep` takes a value as input and then returns the same value, it will pass the value through to the next promise. `sleep` basically becomes Promise chain middleware.

Let's see this written in async/await style:

```javascript
import axios from 'axios'
import sleep from 'mojiscript/threading/sleep'

const fetchJson = url => axios.get(url).then(response => response.data)
const log = msg => (console.log(msg), msg)

const main = async () => {
  const people1 = await fetchJson('https://swapi.co/api/people/1')
  log(people1)
  await sleep(1000)
  const people2 = await fetchJson('https://swapi.co/api/people/2')
  log(people2)
  await sleep(1000)
  const people3 = await fetchJson('https://swapi.co/api/people/3')
  log(people3)
}

main()
```

Now to be honest, I like the problem `sleep` solves, but I'm not quite in love with the syntax of either of those codes I just demonstrated. Between these two examples, I actually think the `async/await` syntax is the worse. `await` is sprinkled all over the place and it's easy too easy to make a mistake.

# Asynchronous Function Composition

Function composition is powerful and will probably take reading many articles to fully understand. Not just the how, but the why. If you want to start, I would recommend starting here: [Functional JavaScript: Function Composition For Every Day Use ](https://hackernoon.com/javascript-functional-composition-for-every-day-use-22421ef65a10).

I'm intentionally not explaining function composition in this article. I believe the syntax I am about to show you is so simple that you do not need to understand function composition at all.

```javascript
import axios from 'axios'
import pipe from 'mojiscript/core/pipe'
import sleep from 'mojiscript/threading/sleep'

const fetchJson = url => axios.get(url).then(response => response.data)
const log = msg => (console.log(msg), msg)

const main = pipe ([
  () => fetchJson('https://swapi.co/api/people/1'),
  log,
  sleep(1000),
  () => fetchJson('https://swapi.co/api/people/2'),
  log,
  sleep(1000),
  () => fetchJson('https://swapi.co/api/people/3'),
  log
])

main()
```

Damn. That is some good looking code!

But since we're already talking about function composition, it would be easy to extract `fetchJson`, `log`, `sleep` into it's own `pipe` and make the code a little more DRY.

```javascript
import axios from 'axios'
import pipe from 'mojiscript/core/pipe'
import sleep from 'mojiscript/threading/sleep'

const fetchJson = url => axios.get(url).then(response => response.data)
const log = msg => (console.log(msg), msg)

const fetchLogWait = pipe ([
  id => fetchJson (`https://swapi.co/api/people/${id}`),
  log,
  sleep(1000)
])

const main = pipe ([
  () => fetchLogWait (1),
  () => fetchLogWait (2),
  () => fetchLogWait (3)
])

main()
```

# Asynchronous map

MojiScript also has the unique ability to **asynchronously** map. (Expect an entire article on this in the near future).

Async map is why I decided to write these examples using [MojiScript](https://github.com/joelnet/MojiScript)'s `pipe` instead of [Ramda](https://ramdajs.com/)'s `pipeP`. Up to this point, the examples will also work just fine with Ramda's `pipeP`. From this point on, the examples are MojiScript exclusive.

Let's see some code! How easy it is to asynchronously `map` the ajax calls?

```javascript
const main = pipe ([
  ({ start, end }) => range (start) (end + 1),
  map (fetchLogWait),
])

main ({ start: 1, end: 3 })
```

Pretty damn easy!

![The text "This changes everything" overlaying a surprised cat](https://thepracticaldev.s3.amazonaws.com/i/rfrzp33kbbj2u07hmsk3.jpeg)

All together in one runnable code block:

```javascript
import axios from 'axios'
import log from 'mojiscript/console/log'
import pipe from 'mojiscript/core/pipe'
import map from 'mojiscript/list/map'
import range from 'mojiscript/list/range'
import sleep from 'mojiscript/threading/sleep'

const fetchJson = pipe ([
  axios.get,
  response => response.data
]) 

const fetchLogWait = pipe ([
  id => fetchJson (`https://swapi.co/api/people/${id}`),
  log,
  sleep (1000)
])

const main = pipe ([
  ({ start, end }) => range (start) (end + 1),
  map(fetchLogWait),
])

main ({ start: 1, end: 3 })
```

Now this code is about as DRY as it gets!

# setTimeout in a for loop

Now if you haven't seen this problem yet, it's given during a lot of JavaScript interviews. The code doesn't run as expected. What is the output?

```javascript
for (var i = 1; i < 6; i++) {
  setTimeout(() => console.log(i), 1000)
}
```

If you didn't guess it pauses for 1 second and then prints five `6`'s all at once, then you would be wrong.

The same program written using `pipe` and MojiScript's `map`. Except this one works as expected, printing the numbers 1 through 5 with a 1 second pause before each output.

```javascript
const sleepThenLog = pipe ([
  sleep (1000),
  log
])

const main = pipe ([
  range (1) (6),
  map (sleepThenLog)
])
```

Want to play more? [Getting started with MojiScript: FizzBuzz](https://dev.to/joelnet/getting-started-with-mojiscript-fizzbuzz-part-1-2fji)

# Things to google

- [Callback Hell](http://www.google.com/search?q=JavaScript+Callback+Hell)
- [Comma Operator](http://www.google.com/search?q=JavaScript+Comma+Operator)
- [Function Composition](http://www.google.com/search?q=JavaScript+Function+Composition)
- [Ramda](https://ramdajs.com)
- [MojiScript](https://github.com/joelnet/MojiScript)

# Summary

Converting sleep into a promise-style function provides additional options to how async code is run.

Ramda's `pipeP` or MojiScript's `pipe` can sometimes be cleaner than `Promises` or `async/await`.

Asynchronous map is powerful.

One caveat, pointed out below, is this implementation does not allow for cancellation. So if you need to `clearTimeout`, you will need to modify this function.

My articles are very Functional JavaScript heavy, if you need more, follow me here, or on Twitter [@joelnet](https://twitter.com/joelnet)!

**Read my other articles:**

[Why async code is so damn confusing (and a how to make it easy)](https://dev.to/joelnet/why-async-code-is-so-damn-confusing-and-a-how-to-make-it-easy-3441)

[How I rediscovered my love for JavaScript after throwing 90% of it in the trash](https://hackernoon.com/how-i-rediscovered-my-love-for-javascript-after-throwing-90-of-it-in-the-trash-f1baed075d1b)

![Cheers!](https://thepracticaldev.s3.amazonaws.com/i/6jsy3a866frzp3u5oda0.jpg)