---
title: Chaining Async Functions like a Boss
teaser: A look at syntactic sugar for chaining async functions in multiple languages.
tags: web,elm,scala,haskell,javascript
author: Joël Quenneville
published_on: 2019-11-01
---

Chaining asynchronous functions is a common problem across languages. JavaScript
has [`Promise`] to deal with this, Elm has [`Task`], and the list goes on.
However, many real-world problems are more complex than straightforward linear
chaining. To solve this, many languages have introduced special syntactic sugar
over their chaining API.

[`Promise`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
[`Task`]: https://package.elm-lang.org/packages/elm/core/latest/Task

## Pseudocode

We want to measure how long an HTTP request takes. To do so, we check the time
before and after the request completes and calculate the difference. In
pseudocode we could say:

```
get the current time
THEN get the user data via HTTP
THEN get the current time
THEN calculate the difference between the start time
     and end time
```

## Elm

In Elm, both HTTP requests and getting the current time are async operations. We
can chain them with [`Task.andThen`]. However, things are not as straightforward
as the pseudocode made it seem.

```elm
Time.now
  |> Task.andThen (\before -> getUserDataViaHttp)
  |> Task.andThen (\_ -> Time.now)
  |> Task.andThen (\after -> 
    -- ???
    -- no access to the before time
    -- in this lambda
  )
```

This is awkward because we need _both_ `before` and `after` at the end of the
pipeline, but `andThen` only has access to the result of the operation
immediately previous.

To get around this, we can start nesting the lambdas so the result of each step
is always in scope for all the following steps. It's really ugly but it gets the
job done 😬.

```elm
timeUserRequest : Task Http.Error Int
timeUserRequest =
  Time.now
    |> Task.andThen (\before ->
      getUserDataViaHttp
        |> Task.andThen (\_ ->
          Time.now
            |> Task.andThen (\after ->
              Task.succeed (after - before)
            )
        )
      )
```

[`Task.andThen`]: https://package.elm-lang.org/packages/elm/core/latest/Task#andThen

## Haskell

Like Elm, Haskell has a function that can be used to chain async operations (the
operator [`=<<`]). To get around the nested lambdas we saw in the Elm example,
Haskell introduces some syntactic sugar: **`do` notation**.

```haskell
do
  before  <- getCurrentTime
  _       <- getUserDataViaHttp
  after   <- getCurrentTime

  return (after - before)
```

This desugars into a bunch of chained `=<<` calls in nested lambdas. The sugared
version is much nicer to read though!

[`=<<`]: https://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Monad.html#v:-62--62--61-

## Scala

Like Elm and Haskell, Scala also has a function that can chain async operations
(theirs is called `flatMap`). Like Haskell, it has a syntactic sugar for those
nested lambdas.  It's called a [**`for` comprehension**] and it's visually
really similar to Haskell's `do` notation.

```scala
for {
  before  <- getCurrentTime
  _       <- getUserDataViaHttp
  after   <- getCurrentTime
} yield (after - before)
```

[**`for` comprehension**]: https://docs.scala-lang.org/tour/for-comprehensions.html

## JavaScript

Like all the other languages here, JavaScript has a method for chaining async
operations ([`Promise.prototype.then`]). It also has some syntactic sugar
([`async/await`]) that makes non-linear chains cleaner. If you squint a bit,
you'll see it's very similar to both Haskell's `do` notation and Scala's `for`
comprehensions.

_Note that while getting the current time can be done syncronously in
JavaScript, I'm using a function that returns a promise here so the example is
similar to the ones we looked at in other languages_.

```javascript
const timeUserRequest = async () => {
  const before = await getCurrentTimeAsync()
  await getUserDataViaHttp()
  const after = await getCurrentTimeAsync()

  return (after - before)
};
```

[`Promise.prototype.then`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
[`async/await`]: https://thoughtbot.com/blog/good-things-come-to-those-who-await

## Chaining elsewhere

While chaining with `then` is promise-specific in JavaScript, the other
languages examined in this article use their chaining functions for many other
constructs - not just for async operations.

For Haskell and Scala, that means that their syntactic sugar notations can be
used for all chainable structures. If you work with these languages you will
encounter the `do` / `for` sugar everywhere from IO operations to null-checking,
to JSON parsing.
