JavaScript is single-threaded, meaning it can only do one thing at a time. Asynchronous programming lets you start long-running operations (network requests, timers, file reads) without blocking the rest of your code.
The Event Loop
The event loop is how JavaScript handles asynchronous code. Understanding it is fundamental.
Even with a 0ms delay, the timeout callback runs after the synchronous code finishes. The event loop processes the call stack first, then checks the callback queue.
Callbacks
A callback is a function passed to another function to be called later.
Callback Hell
Nested callbacks quickly become unreadable:
This is why promises were invented.
Promises
A Promise represents a value that may not be available yet. It has three states: pending, fulfilled, or rejected.
Creating a Promise
Consuming Promises with .then() and .catch()
Promise Chaining
Chaining flattens the callback hell pattern:
Async/Await
async/await is syntactic sugar over promises that makes asynchronous code look synchronous.
Rewriting the Callback Hell Example
Clean, readable, and easy to debug.
The Fetch API
fetch is the modern way to make HTTP requests in the browser.
GET Request
POST Request
Always Check response.ok
A common mistake is forgetting that fetch does not throw on HTTP errors like 404 or 500. You must check response.ok manually.
Running Promises in Parallel
Promise.all
Wait for all promises to resolve. Rejects if any one fails.
Promise.allSettled
Wait for all promises to complete, regardless of success or failure.
Promise.race
Returns the result of whichever promise settles first.
Error Handling Patterns
Try/Catch with Async/Await
Practical Exercise
Build a simple API data loader:
Key Takeaways
- JavaScript uses the event loop to handle async operations on a single thread.
- Promises replace nested callbacks with chainable
.then()calls. async/awaitmakes promise-based code read like synchronous code.- Always check
response.okwhen usingfetch— it does not throw on HTTP errors. - Use
Promise.allfor parallel requests andPromise.allSettledwhen you need results from all regardless of failures.