DEV Community

Neural Download
Neural Download

Posted on

Async Await Is Just a Bookmark

https://www.youtube.com/watch?v=2ulRI-a5ea0

Here's what most developers think async/await does: you call an async function, and it runs on a separate thread. Maybe a background worker. Something parallel.

Wrong. Async/await does not create threads. It does not run things in parallel. One thread. One function at a time. Always.

So how does your app handle a thousand network requests on a single thread?

The Compiler Rewrites Your Function

When you write an async function, the compiler doesn't keep it as a function. It transforms it into a state machine.

Each await keyword becomes a checkpoint. State 0 runs the code before the first await. State 1 runs the code between the first and second await. State 2 picks up after that.

The function remembers which state it's in and all its local variables. When execution hits an await, the function doesn't block. It doesn't spin. It saves its state and returns control to the caller.

The function literally pauses itself.

The Bookmark Metaphor

Think of it like a bookmark in a book. You're reading chapter three, you hit a page that says "waiting for data." Instead of staring at that page, you place a bookmark, close the book, and go read a different book.

When the data arrives, you pick up your first book, flip to the bookmark, and keep reading from exactly where you stopped.

That's what a coroutine is — a function that can pause and resume. Not by blocking a thread. Not by creating a new one. Just by saving where it was and stepping aside.

The real magic is what happens during that pause. While your function is suspended, the thread is completely free. It can run other coroutines, other callbacks. One thread, doing the work of thousands.

Who Decides What Runs Next?

The event loop. It's a simple while True loop that checks a queue. If there's a coroutine ready to resume, it runs it until the next await. Then it checks the queue again.

When a coroutine awaits something — a network response, a file read, a timer — that request goes to the operating system. The OS handles the actual waiting. Not your thread. Not your CPU.

When the OS says "your data is here," it puts a notification in the event loop's queue. The loop picks it up, finds the suspended coroutine, and resumes it from its saved state.

Component Role
async function Declares a pausable function (coroutine)
await Pause point — saves state, yields control
State machine What the compiler actually produces
Event loop The scheduler — decides what runs next
OS Handles the real I/O waiting

This is why async is perfect for I/O-bound work. Your program spends most of its time waiting — waiting for databases, APIs, files. Async lets one thread juggle all that waiting without wasting CPU cycles.

The Secret Origin: Generators

Here's something most tutorials won't tell you. Async/await wasn't invented from scratch. It was built on top of generators.

A generator is a function with a yield keyword. Each time you call next(), it runs until the next yield, returns a value, and pauses. Call next() again, it picks up right where it left off.

Sound familiar? That's exactly what async functions do. await is yield in disguise. The compiler transforms your async function into a generator-like state machine that yields at every await point.

# Generator — pauses at yield
def counter():
    yield 1
    yield 2
    yield 3

# Async — pauses at await
async def fetch():
    data = await get("/api")
    result = await process(data)
    return result
Enter fullscreen mode Exit fullscreen mode

Python literally built async/await by wrapping generators with extra scheduling logic. JavaScript did the same thing. C# compiles async methods into state machine classes. Different syntax, same core idea.

Every async function you've ever written is just a pausable function wearing a fancy hat.

Watch the full animated breakdown: Async Await Is Just a Bookmark

Neural Download — visual mental models for the systems you use but don't fully understand.

Top comments (0)