Skip to content
Latchkey

What Is Async/Await? Writing Asynchronous Code Cleanly

Async/await is syntax that lets you write non-blocking, asynchronous code in a straight-line style that reads almost like normal sequential code.

Asynchronous code lets a program start a slow operation (a network call, a disk read) and keep doing other work instead of blocking until it finishes. Historically that meant nested callbacks. Async/await is syntactic sugar over promises (or futures) that flattens those callbacks into code you can read top to bottom, while still being non-blocking underneath.

The problem async/await solves

Without it, asynchronous work means callbacks or chained promises, which nest and tangle as logic grows. Async/await lets you await a result as if it were synchronous, while the runtime frees the thread to do other work until the result is ready.

How it works underneath

An async function returns a promise. When it hits an await, it suspends and yields control back to the event loop; when the awaited promise resolves, the function resumes where it left off. No thread is blocked during the wait.

Common mistakes

  • Forgetting to await a promise, so code runs before it is ready.
  • Awaiting in a loop when calls could run concurrently.
  • Not handling rejected promises, leading to unhandled errors.
  • Assuming async code is parallel; on one thread it is interleaved.

Async is not the same as parallel

On a single-threaded runtime like Node.js, async/await interleaves work; it does not run JavaScript in parallel. It shines for I/O-bound work (waiting on the network) but does not speed up CPU-bound computation.

A quick example

Writing const data = await fetch(url); reads like a blocking call, but the runtime is free to handle other work while the network request is in flight, then resumes this line when the response arrives.

Async/await in CI

A frequent flaky-test cause is a forgotten await: the test asserts before the async work finishes, passing or failing by timing. These races fail intermittently on busy runners. Latchkey can auto-retry transient failures while you fix the missing await, so one flaky run does not block a merge.

Key takeaways

  • Async/await writes non-blocking code in a readable, sequential style.
  • An async function suspends at await and resumes when the awaited promise resolves.
  • It is great for I/O but is not parallelism; forgotten awaits cause flaky tests.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →