skip to content

async / await

async starts a coroutine that produces a value, returning a Deferred you await later, which is how you run independent calls in parallel. The pattern to have ready is starting several asyncs first and only then awaiting them.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What does the async coroutine builder return, and how do you get the result out of it?

level: juniorimportance: must knowfreq 80%

answer

  1. async returns Deferred<T>
  2. await() suspends to get value
  3. launch=Job, async=Deferred
  4. starts eagerly by default
  5. await rethrows the exception

basics

~10 s

async starts a background task and hands you a Deferred. You call await() on it to wait for and receive the result value.

solid answer

~40 s

async is a coroutine builder on CoroutineScope that starts a new coroutine and immediately returns a Deferred<T> — a future-like handle. The coroutine runs concurrently; you don't get the value back from async itself. To obtain the computed value you call the suspending function await() on the Deferred, which suspends the caller until the result is ready and then returns it (or rethrows any exception the coroutine threw). Use async when you want a value back; use launch when you only need a side effect (it returns Job, not Deferred). Both start eagerly by default. await() does not block a thread — it suspends, so other work can proceed on the same thread.

code

kotlin · 4 lines
kotlin
suspend fun price(): Int = coroutineScope {
    val d: Deferred<Int> = async { 21 * 2 }
    d.await() // 42
}

go deeper

for a junior

Knows async returns Deferred and await() retrieves the value; distinguishes it from launch.

for a middle

Explains suspension vs blocking and eager start, and that await rethrows exceptions.

for a senior

Frames async as scope-bound structured concurrency and notes CoroutineStart.LAZY and Deferred-is-a-Job.

for a principal

Discusses when returning Deferred across API boundaries is appropriate vs keeping it internal to a scope.

## What `async` is `async` is a **coroutine builder**: a function that starts a new coroutine. It is an extension on `CoroutineScope`. Unlike `launch` (which returns a `Job` and is used for fire-and-forget side effects), `async` returns a **`Deferred<T>`**. ## `Deferred<T>` `Deferred<T>` is a `Job` that also carries a **future result** of type `T`. Think of it as a promise/future: a handle to a value that will exist later. Because `Deferred` *is a* `Job`, it also has lifecycle methods like `cancel()` and `isActive`. ## `await()` To read the value you call `await()`, a **suspending function**. "Suspending" means it can pause the current coroutine without blocking the underlying thread, freeing that thread for other work, and resume later when the result is ready. - If the coroutine already finished, `await()` returns immediately. - If it is still running, `await()` **suspends** until completion. - If the coroutine threw, `await()` **rethrows** that exception. ```kotlin suspend fun loadUser(): User = coroutineScope { val deferred: Deferred<User> = async { fetchUserFromDb() } // starts now // ... can do other work here while it runs ... deferred.await() // suspend until the value is ready, then return it } ``` ## Eager start By default `async` uses `CoroutineStart.DEFAULT`, so the coroutine begins **eagerly** as soon as `async` is called — not lazily when `await()` is invoked. (You can pass `start = CoroutineStart.LAZY` to defer it until `await()` or `start()`.) ## Key keywords/APIs - `async { ... }` — builder returning `Deferred<T>` - `Deferred<T>` — future-like Job carrying a result - `await()` — suspends to obtain the value or rethrow - contrast `launch` → `Job` (no result)

  • What does launch return instead, and when would you use it?
    launch returns a Job (no result value). Use it for fire-and-forget side effects where you don't need a return value.
  • Does calling await() block the thread?
    No. await() is a suspending function: it suspends the coroutine and frees the thread; it doesn't block it.

async is a coat-check ticket: you hand off work, get a ticket (Deferred), and redeem it later with await().

saying these in an interview costs you the question

  • Saying async returns the value directly instead of a Deferred
  • Claiming await() blocks the calling thread
  • Confusing async (Deferred) with launch (Job)
  • Thinking async only starts when await() is called (it's eager by default)

context

open as a page

How do you run two independent suspending calls concurrently and combine their results, and how is that different from calling them one after another?

level: middleimportance: must knowfreq 75%

basics

~10 s

Start each call with async so they run at the same time, then await both. Calling them sequentially (just suspend calls) waits for the first to finish before starting the second, so it's slower.

open as a page

How are exceptions handled when an async coroutine throws? When is the exception delivered, and how does the enclosing scope affect propagation?

level: seniorimportance: must knowfreq 60%

basics

~20 s

An exception from async is stored in its Deferred and rethrown when you call await(). But under a normal coroutineScope it also cancels the parent and siblings immediately, so the failure surfaces even before you await.

open as a page

When you fan out into a list of Deferreds, what does awaitAll do, and how does it behave on failure compared to awaiting in a loop?

level: middleimportance: should knowfreq 55%

basics

~10 s

awaitAll waits for every Deferred in a list and returns all their results as a list. If any one fails, awaitAll fails fast immediately instead of waiting for the slower remaining ones.

open as a page

What does start = CoroutineStart.LAZY change about async, and what is a subtle pitfall of lazy Deferreds in parallel decomposition?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

LAZY means the async coroutine doesn't start until you trigger it (via await() or start()). The pitfall: if you rely on await() to start lazy tasks, they run one at a time instead of in parallel.

open as a page