Kotlin’s suspend functions compared to JavaScript’s async/await

Joffrey Bion
3 min readDec 6, 2018

--

With the release of Kotlin 1.3, coroutines went out of experimental status, so I felt like writing about them to help people understand what they are and how they work, and also because explaining is the best way to learn something.

When writing examples, I realized that Kotlin’s suspend functions felt like JavaScript's async functions to JavaScript developers, so I decided to write about the differences and similarities in this separate story in order to avoid confusions.

TL;DR

Let’s assume myAsyncFunc is a JavaScript async function, and mySuspendFunc is a Kotlin suspend function, both declared with the same body. We can draw the following parallel:

  • JavaScript myAsyncFunc() is similar to Kotlin async { mySuspendFunc() }
  • Kotlin mySuspendFunc() is similar to JavaScript await myAsyncFunc()

In short, Kotlin explicitly declares at the call site that the call is asynchronous via the async() function call. On the other hand, if something looks like a normal function call, it is implicitly synchronous and we can expect a result directly.

In JavaScript, normal calls of an async function are implicitly asynchronous, because they return a Promise. JavaScript is explicit about making these calls synchronous via await.

We want to see code!

Let’s compare these 2 snippets. Note that I aligned the line numbers for easier comparison.

We should note that these are not exactly equivalent at every function level, but the call chain of normalFunction() as a whole is roughly equivalent.

The similarities

To come back to the 2 points I made in the TL;DR, let’s look at lines 19 and 11.

They both can do async stuff

Line 19 represents an asynchronous call in both snippets. Calling an async function directly (without await) in JavaScript returns immediately and returns a Promise.

This is similar to wrapping a Kotlin suspending function call into an async() library function call, which returns immediately too (so it’s asynchronous), and returns a Deferred<T>.

They both replace the callback hell

Line 11 represents a synchronous call in both snippets. Calling a suspend function in Kotlin is similar to using await + an async function call in JavaScript.

Behind the scenes, suspending functions are technically an abstraction over callbacks* to allow you to write sequential code, just like await kind of unfolds Promise callbacks. In order to do this “callback unfolding magic”, calling a suspending function requires the caller function to be declared suspend, just like using await in JavaScript forces you to declare your function with async.

*To be taken with a grain of salt. Neither Kotlin nor JavaScript (AFAIK) actually de-sugars this code into callbacks. They internally use state machines instead, for better efficiency. However, it gives the same apparent behavior from the outside.

The differences

From afar: they have different defaults

JavaScript and Kotlin have different opinions as to what should be the default behavior and what needs to be explicitly stated in the code.

Kotlin suspending functions are synchronous by default, which means if you call them without special syntax, you can expect what a normal function call would do: wait for execution of the function and return the resulting value. They can be wrapped in coroutine builders like async() to get an asynchronous behavior (this creates a new coroutine to execute the suspending function passed as parameter).

JavaScript async functions are asynchronous by default. They return a Promise and return immediately when called without special syntax. They have to be explicitly await-ed if we want to call them synchronously and wait for their result.

A closer look: they don’t do the same things in the same place

What appears to be syntactic differences is in fact slightly more. The async keyword in JavaScript does multiple things:

  • it allows the “callback unfolding magic” of await, like suspend in Kotlin allows calls to other suspending functions
  • it also makes the function asynchronous and wraps the return value (or error) into a Promise.

Kotlin sees that second point as a separate thing, and requires you to do something else to express asynchronous calls explicitly (starting a coroutine).

I feel like drawing parallels like this can help people grasp faster how both suspending functions and JavaScript async/await works, and I hope this helped you. If you find something misleading or incorrect in what I said here, please don’t hesitate to comment. Cheers!

--

--