liveBook · Manning

Async

As explained in Kotlin in Action, 2E

async is a coroutine builder that starts an asynchronous computation and produces a handle for obtaining its result.

`async` starts a coroutine that computes a value asynchronously and returns `Deferred<T>`. Call the suspending `await()` function on that handle to obtain the value. Unlike `launch`, which is suited to start-and-forget side effects, `async` is for work whose result will be consumed. section 14.6.3 section 14.6.3

Start independent work together

```kotlin fun main() = runBlocking { val first = async { slowlyAddNumbers(2, 2) } val second = async { slowlyAddNumbers(4, 4) } println(first.await()) println(second.await()) } ``` Each `async` call starts a new coroutine without suspending the caller. The caller suspends at `await()` only until that particular result is ready. When the computations are independent, both delays can overlap, so total time is roughly that of the longest computation rather than their sum. section 14.6.3 section 14.6.3

Use `async` deliberately rather than wrapping every suspending call. Sequential suspending calls already express sequential work without blocking the underlying thread. `async` adds value when tasks can begin independently and their results are needed later, such as loading two images before combining them. section 14.6.3 section 1.2.4

suspend fun loadAndOverlay(first: String, second: String): Image =
    coroutineScope {
        val firstDeferred = async { loadImage(first) }                  #1
        val secondDeferred = async { loadImage(second) }                #2
        combineImages(firstDeferred.await(), secondDeferred.await())    #3
    }

This example shows the usual result-oriented pattern: create two `Deferred` values in one `coroutineScope`, await both, then combine their completed values. section 1.2.4

An `async` coroutine belongs to a `CoroutineScope`. When started inside another coroutine builder, it becomes a child coroutine, so structured concurrency tracks it as part of the parent’s lifetime. This relationship also matters for failure: an uncaught child exception propagates to its parent and can cancel sibling coroutines in a regular, nonsupervisor scope. section 15.1 section 18.2.1

Treat `await()` as an error boundary for a deferred result. If the `async` block fails, `await()` rethrows that exception because no value of the expected type is available; surround `await()` with `try-catch` when the consumer handles it. Catching only around the `async` call does not catch an exception thrown later inside its new coroutine. section 18.1 section 18.1

A top-level `async` has a distinct exception-handling role: `CoroutineExceptionHandler` is not invoked for it. The consumer of its `Deferred` is responsible for observing failure through `await()`, though uncaught failure can still trigger cancellation unless a `SupervisorJob` changes that scope behavior. section 18.3.1 section 18.3.1

How Kotlin in Action, 2E covers it

How deep it goes
Defines `Deferred<T>` and `await()`, demonstrates concurrent execution, and details structured failure and exception-handler behavior.
Examples
Demonstrates parallel number addition and concurrent image loading followed by result combination.
What you can do after
Apply Kotlin coroutines to run independent value-producing tasks concurrently and handle their results or failures through `await()`.
How it connects
Connects `async` to `Deferred`, `await`, suspending functions, `CoroutineScope`, structured concurrency, `SupervisorJob`, and `CoroutineExceptionHandler`.

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.