Use async/await when it makes a dependent sequence easier to follow as steps; use .then() when a compact transformation chain is clearer. Both use the same promise model. For independent operations, start them before combining their results rather than awaiting them one by one.
How do async/await and promises relate?
async/await is syntax built on promises, not a separate asynchronous system. An async function returns a promise. Inside it, await waits for a promise to settle and makes its fulfilled value available to the surrounding function. Top-level await is also permitted in supported module contexts.
As an Amazon Associate I earn from qualifying purchases.
In a promise chain, each .then() returns a new promise. A handler can return a plain value or another promise, and the next handler receives the resulting value once it is available. MDN summarizes the relationship: “async/await has the same concurrency semantics as normal promise chains.”
What does each style look like?
Here is the same dependent workflow in both styles: obtain a URL, fetch a response, parse its JSON, then use the data.
#1 Best Overall
Promise chain
function logIngredients() {
return doSomething()
.then((url) => fetch(url))
.then((response) => response.json())
.then((data) => {
listOfIngredients.push(data);
console.log(listOfIngredients);
});
}
async/await
async function logIngredients() {
const url = await doSomething();
const response = await fetch(url);
const data = await response.json();
listOfIngredients.push(data);
console.log(listOfIngredients);
}
The chain emphasizes successive handlers; the async function makes each intermediate value a local variable. In production, decide whether the function should return the parsed data, check the HTTP response status where appropriate, and define how errors should be handled.
When should you choose each style?
| Situation | Promise chaining | async/await | Practical choice |
|---|---|---|---|
| Dependent steps | Return a value or promise from each handler for the next handler. | Use sequential await statements to show each dependency. |
Choose whichever makes the data flow easiest to see. |
| Independent operations | Start operations before composing their promises, for example with Promise.all(). |
Start operations first, then await a combined result. | Do not await independent work one operation at a time when it can safely proceed together. |
| Error handling | Use a rejection handler in .then() or attach .catch(). |
Use try/catch around awaited operations. |
Handle errors near the operation if recovery is local; otherwise let them reach an intentional boundary. |
| Transformations and branching | A short transformation pipeline can read directly as a chain. | Local variables and branching can be clearer in an imperative workflow. | Prefer the clearer form and stay consistent with the surrounding code. |
Neither syntax is inherently faster or more concurrent. Runtime behavior follows promise settlement and handler scheduling; concurrency depends on when operations start and how their promises are composed.
Rank #2
How do you run independent promises concurrently?
Two separate await expressions run in sequence: the second operation does not start until execution reaches it. If the operations do not depend on one another, start both first and then await them together:
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteconst userPromise = getUser();
const settingsPromise = getSettings();
const [user, settings] = await Promise.all([userPromise, settingsPromise]);
Promise.all() rejects its aggregate when any input rejects. It does not cancel the other operations; they continue, but their individual outcomes are not returned through that rejected aggregate. Use Promise.allSettled() when you need every operation’s fulfilled or rejected outcome, even if some fail. The same composition methods work with promise chains: the syntax choice does not determine whether the work starts concurrently.
How does error handling differ?
In a chain, a rejection propagates to later rejection handlers until one handles it. .catch(handler) is shorthand for .then(undefined, handler). If the handler returns a value, the promise produced by .catch() fulfills with that value; if it throws or returns a rejected promise, the failure continues.
In an async function, rejection of an awaited promise is thrown at the await expression, where a surrounding try/catch can handle it:
Rank #4
async function loadData() {
try {
const response = await fetchData();
return await response.json();
} catch (error) {
// Handle or rethrow the failure deliberately.
throw error;
}
}
Be deliberate about fallback values: returning one from a catch handler turns that failure path into a fulfilled promise. In either style, place recovery where you know what action is appropriate rather than swallowing errors accidentally.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsDoes await block JavaScript?
await pauses the rest of its surrounding async function until the awaited operation settles; it does not block the entire program. Other asynchronous work can continue. What matters for independent tasks is whether you start them before awaiting their combined result.
Best Value
Which promise composition method should you use?
Promise.all()fulfills when all inputs fulfill and rejects if an input rejects; use it when all results are needed and any failure should fail the combined operation.Promise.allSettled()waits for all inputs to settle and gives each outcome; use it when partial failures should not hide the rest.Promise.any()andPromise.race()provide other composition behaviors when their settlement rules match the task.
These are promise-composition choices, not alternatives to async/await. You can await their results or use them in a chain.
Common misconceptions
- “async/await is always faster.” The syntax alone does not establish a performance advantage.
- “await makes JavaScript synchronous.” It pauses the surrounding async function, not the whole program.
- “Promise.all() cancels the remaining requests when one fails.” It rejects the aggregate, but does not cancel the other operations.
For introductory explanations and reference details, see MDN’s guides to using promises, the Promise object, async functions, and the await operator.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Free tools Windows power users keep installed
One-click scans. No signup required.




