JavaScript Fetch: Using .then() vs await
The fetch() API was introduced in 2015 as part of the WHATWG Fetch Living Standard,
designed to modernise and eventually replace XMLHttpRequest. It provides a cleaner,
promise-based interface for making HTTP requests and became widely adopted once browser support
spread across Chrome, Firefox, Edge and Safari.
Today, fetch() is the de-facto way to make web requests in the browser and Node.js.
Using .then()
Before async/await existed, promises were typically consumed using
.then() chains. This works fine, but can become harder to read when there are
multiple steps.
// Using .then()
fetch("https://randomuser.me/api/")
.then(response => response.json())
.then(data => {
const user = data.results[0];
console.log(user);
})
.catch(err => console.error(err));
Using await
Introduced in ES2017 (ES8), async / await lets you write
asynchronous code that looks synchronous. It's cleaner, easier to read, and avoids deep
.then() chains.
async function getUser()
{
const r = await fetch("https://randomuser.me/api/");
const d = await r.json();
const user = d.results[0];
return user;
}
var user = await getUser();
console.log(user);
Key Differences
- Readability:
await makes sequential async steps look natural.
- Error handling:
try/catch with await is clearer than chained .catch().
- Chaining:
.then() is sometimes useful when you want to pipeline transformations.
- Inside functions:
await can only be used inside an async function (or top-level modules), whereas .then() works anywhere.
When to Use Which?
- Use
await for most modern code — it’s simpler and more readable.
- Use
.then() when you want functional-style chaining or cannot mark the caller as async.
How Each await Maps to .then()
The await keyword is simply syntactic sugar over promises.
Each await corresponds to one implicit .then() call.
Below is a breakdown using the original function.
Using await
async function getUser()
{
const r = await fetch("https://randomuser.me/api/");
const d = await r.json();
const user = d.results[0];
return user;
}
Equivalent .then() Version
Each await maps to a .then() like this:
-
await fetch(...)
→ becomes
fetch("https://randomuser.me/api/").then(r => {
-
await r.json()
→ becomes another nested .then()
fetch("https://randomuser.me/api/")
.then(r => r.json())
.then(d => {
-
return user;
→ becomes the final value resolved by the chain
fetch("https://randomuser.me/api/")
.then(r => r.json())
.then(d => d.results[0]);
Full .then() Equivalent of the Entire Function
function getUser() {
return fetch("https://randomuser.me/api/")
.then(r => r.json())
.then(d => d.results[0]);
}
So the mapping is:
await A → .then(A => ...)
await B → .then(B => ...)
return value → resolves the promise returned by the function
Using await makes the flow look linear, but under the hood, JavaScript
is still building this chain of .then() calls.
```

















