liveBook · Manning

Async/await

As explained in Kotlin in Action, 2E

await is an operation that suspends a coroutine until an asynchronous computation's result is available.

Kotlin’s async/await pattern starts independent computations concurrently and then suspends until their results are available. async returns Deferred<T>; await retrieves its value without blocking the underlying thread. section 14.6.3 section 1.2.4

Listing 14.7 Using the async coroutine builder to start a new coroutine
suspend fun slowlyAddNumbers(a: Int, b: Int): Int {
    log("Waiting a bit before calculating $a + $b")
    delay(100.milliseconds * a)
    return a + b
}
 
 
fun main() = runBlocking {
    log("Starting the async computation")
    val myFirstDeferred = async { slowlyAddNumbers(2, 2) }    #1
    val mySecondDeferred = async { slowlyAddNumbers(4, 4) }   #1
    log("Waiting for the deferred value to be available")
    log("The first result: ${myFirstDeferred.await()}")       #2
    log("The second result: ${mySecondDeferred.await()}")     #2
}

Start two slowlyAddNumbers calls with async, then call await on each Deferred. The computations overlap, so total time follows the longer operation rather than their sum. section 14.6.3 section 14.6.3

The builder invocation itself does not suspend the surrounding coroutine. It creates work immediately; the surrounding coroutine suspends only when await needs a result. In the example, both additions begin before either result is requested. section 14.6.3

Use async/await selectively:

  • Choose async when independent tasks should run concurrently and their values must be combined. section 14.6.3
  • Prefer ordinary sequential suspending-function calls when concurrency is unnecessary; async is not required for every asynchronous operation. section 14.6.3
  • Keep related async operations in one coroutine scope so failure in one loading process can cancel the other automatically. section 1.2.4

Handling a failed Deferred

A failed async computation does not produce a value. Calling await rethrows its exception, so surround await with try-catch when the caller should handle the failure. An uncaught child exception can still propagate to its parent coroutine. section 18.1 section 18.3.1

This pattern resembles a Future or Promise: Deferred represents a value whose computation is still in progress. It provides readable consecutive logic without callback-heavy control flow while retaining structured coroutine lifetimes. section 14.6.3 section 1.2.4

How Kotlin in Action, 2E covers it

How deep it goes
Explains Deferred creation, suspension timing, concurrency, structured cancellation, and exception propagation through await.
Examples
Uses concurrent number additions, concurrent image loading, and a Deferred that rethrows UnsupportedOperationException from await.
What it assumes
Assumes coroutine and suspending-function basics while clarifying when async is unnecessary for sequential asynchronous calls.
What you can do after
Apply it via Kotlin coroutines to run independent tasks concurrently, await their values, combine results, and catch failures.
How it connects
Connects async/await with coroutines, suspending functions, Deferred, structured concurrency, coroutine scopes, and exception handling.

Also explained in

Compare how 17 books explain async/await →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.