Async Await

Consuming and building promises are both second nature by now. Since ES2017 there's an even easier way to consume them: async/await.

July 11, 20263 min read17 / 22

Consuming and building Promises are both second nature by now, chained straight through post 16. Since ES2017 there's an easier way to consume them, async/await.

Marking a Function async

Adding async in front of a function changes what it is: an async function runs in the background while its own code executes, and (more on this in a future post) automatically returns a Promise once it finishes.

JavaScript · Live Editor
Loading editor...

Hit Run. 'FIRST' prints before the response does, proof the function really is running in the background, exactly like fetch always has.

await Pauses the Function, Not the Program

await needs a Promise, and it stops execution at that exact line, inside the function, until the Promise settles. That sounds like blocking. It isn't.

The function itself is already off running asynchronously, so pausing inside it never touches the main thread. That's the whole trick behind async/await: code that reads top to bottom, like ordinary synchronous code, while everything underneath it stays exactly as asynchronous as .then() ever was.

The same fetch-then-render sequence written as a .then() chain versus async/await, same steps, same asynchronous behavior underneath, different reading order. ExpandThe same fetch-then-render sequence written as a .then() chain versus async/await, same steps, same asynchronous behavior underneath, different reading order.

It's Sugar Over .then()

const res = await fetch(url); and fetch(url).then((res) => {...}) do the exact same thing. await just hands the resolved value straight to a variable instead of a callback parameter, no new asynchronous machinery underneath, just a different way of writing the same consumption.

Rebuilding whereAmI With await Throughout

Every await replaces what used to be a separate .then() step, and the whole function collapses into something that reads like a straight list of instructions. Worth being precise about: async/await only changes how a Promise gets consumed. getPosition, built with new Promise(...) back in post 15, doesn't change at all, it's still exactly the same Promise, just awaited here instead of chained with .then().

JavaScript · Live Editor
Loading editor...

Hit Run, allow location access, and the same card post 15's promise chain rendered shows up again, five awaited steps, zero .then() calls, zero callback parameters.

One thing deliberately missing here: no error handling at all. Deny location access, or hit the geocoding API's rate limit, and this whole function falls apart with nothing catching it. That's not an oversight, .then()'s .catch() doesn't attach the same way to await, and fixing that properly is next.

The Essentials

  1. async in front of a function makes it run in the background, returning a Promise automatically once it finishes.
  2. await pauses only the function it's inside of, not the main thread, since the function is already running asynchronously.
  3. async/await is syntactic sugar over .then(), no new asynchronous behavior, just a different way of writing the same consumption.
  4. Each await replaces a .then() step, turning a chain into code that reads top to bottom.
  5. async/await has no built-in error handling of its own yet, a rejected await currently has nowhere to go.