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.