JavaScript 43 🧬 async/await
async function fetchData() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return data;
}
fetchData().then(data => console.log(data));
async function run() {
try {
const result = await fetchData();
console.log(result);
} catch (err) {
console.error('Failed:', err.message);
} finally {
console.log('Done');
}
}
run();
const p1 = fetchData();
const p2 = fetchData();
const [a, b] = await Promise.all([p1, p2]);
async function sequential() {
const a = await step1();
const b = await step2(a);
return step3(b);
}
async function parallel() {
const [a, b] = await Promise.all([step1(), step2()]);
return [a, b];
}
async and await are the syntax sugar on top of Promises that makes asynchronous code read like synchronous code. Instead of chaining .then() calls, you write await in front of a Promise — and the function pauses until the Promise settles, without blocking the rest of the program.
Key point: async marks a function as returning a Promise. await pauses inside that function until a Promise resolves, then returns the value — or throws if it rejects. The magic is that it doesn’t block the main thread. Other code keeps running while the awaited Promise is pending.
a – What is async/await
async and await are two keywords that go together. async before a function makes it return a Promise. await inside an async function pauses execution until a Promise settles.
The async keyword:
async function greet() {
return 'Hello';
}
greet().then(v => console.log(v));
// [ Hello ]
Even though greet returns a string, the function wraps it in a resolved Promise. You can .then() it.
Equivalent without async:
function greet() {
return Promise.resolve('Hello');
}
async is just sugar — it means “always return a Promise”.
The await keyword:
async function run() {
const value = await Promise.resolve(42);
console.log(value);
}
run();
// [ 42 ]
await waits for the Promise to resolve, then returns its value. If the Promise rejects, await throws the rejection reason.
What await really does:
┌──────────────────────────────────────────────┐
│ await somePromise │
│ │
│ 1. Pause execution of the async function │
│ 2. Return control to the caller │
│ 3. Wait for the Promise to settle │
│ 4. Resume with the resolved value │
│ OR throw the rejection reason │
│ │
│ The rest of the program keeps running. │
│ Only this function pauses. │
│ │
└──────────────────────────────────────────────┘
Key rules:
| Rule | Meaning |
|---|---|
await only works inside async functions | Else syntax error |
async functions always return a Promise | Even for plain returns |
await pauses only the async function | Not the whole program |
await throws on rejection | Wrap in try/catch |
await on non-Promise values | Wraps them and resolves immediately |
Top-level await | Works in ES modules only |
await works on any value:
async function run() {
const a = await 42; // wraps in Promise.resolve(42)
const b = await Promise.resolve('hi');
console.log(a, b);
}
run();
// [ 42 hi ]
You can await anything. If it’s a Promise, it waits. If it’s a plain value, it resolves immediately.
Async functions return Promises — always:
async function getValue() {
return 42;
}
console.log(getValue());
// [ Promise { 42 } ]
getValue().then(v => console.log(v));
// [ 42 ]
Even a plain return in an async function gets wrapped in a Promise.
Async functions and thrown errors:
async function fails() {
throw new Error('boom');
}
fails().catch(err => console.log(err.message));
// [ boom ]
A throw inside an async function rejects the returned Promise.
Comparing Promise chains to async/await:
// Promise chain
function loadUser() {
return fetch('/user')
.then(res => res.json())
.then(user => fetch(`/orders/${user.id}`))
.then(res => res.json())
.catch(err => console.error(err));
}
// async/await
async function loadUser() {
try {
const res = await fetch('/user');
const user = await res.json();
const orderRes = await fetch(`/orders/${user.id}`);
return await orderRes.json();
} catch (err) {
console.error(err);
}
}
Both do the same thing. The async/await version reads top-to-bottom like sync code.
Why async/await matters:
- Readability — no
.then()pyramid - Error handling —
try/catchworks like sync code - Debugging — stack traces point to the right line
- Logic — conditionals, loops, and
if/elsework naturally - Adoption — every modern API returns Promises
When to use async/await vs .then():
| Situation | Preferred |
|---|---|
| Multi-step async logic | async/await |
| Complex error handling | async/await |
| Simple one-off | .then() |
| Combining Promises | Promise.all + await |
| Inside callbacks | Either |
In practice, async/await wins most of the time.
b – async/await syntax and usage
The syntax is straightforward once you know the rules. This section covers all the forms and patterns.
Basic async function:
async function doWork() {
const result = await someAsyncTask();
return result;
}
Async arrow function:
const doWork = async () => {
const result = await someAsyncTask();
return result;
};
Async method in an object:
const obj = {
async doWork() {
return await someAsyncTask();
}
};
Async method in a class:
class Service {
async fetchUser(id) {
const res = await fetch(`/users/${id}`);
return res.json();
}
}
Async IIFE (immediately invoked function expression):
(async () => {
const data = await fetchData();
console.log(data);
})();
Useful for running async code at the top level of older scripts.
await on function calls:
async function main() {
const user = await getUser(1);
const orders = await getOrders(user.id);
const details = await getDetails(orders[0].id);
return details;
}
Each await pauses until the Promise settles.
await on Promise.all:
async function load() {
const [user, orders, products] = await Promise.all([
fetch('/user').then(r => r.json()),
fetch('/orders').then(r => r.json()),
fetch('/products').then(r => r.json())
]);
return { user, orders, products };
}
All three run in parallel; await waits for all of them.
await on Promise.allSettled:
async function loadTolerant() {
const results = await Promise.allSettled([a(), b(), c()]);
return results.map(r => r.status === 'fulfilled' ? r.value : null);
}
Sequential vs parallel — the key decision:
// Sequential — each waits for the previous
async function sequential() {
const a = await slowStep1();
const b = await slowStep2(); // starts after step1
const c = await slowStep3(); // starts after step2
return [a, b, c];
}
// Total time: 1 + 2 + 3 = 6 seconds
// Parallel — all start at once
async function parallel() {
const [a, b, c] = await Promise.all([
slowStep1(),
slowStep2(),
slowStep3()
]);
return [a, b, c];
}
// Total time: max(1, 2, 3) = 3 seconds
A common mistake — forgetting await:
async function wrong() {
const data = fetch('/data'); // ❌ no await
console.log(data); // Promise, not data
}
async function right() {
const data = await fetch('/data'); // ✅
console.log(data); // Response
}
Without await, you get the Promise itself, not its resolved value.
Awaiting in a loop — the trap:
// ❌ Sequential — slow
for (const url of urls) {
const data = await fetch(url);
results.push(data);
}
// ✅ Parallel — fast
const results = await Promise.all(urls.map(u => fetch(u)));
If the operations are independent, don’t await inside a loop — use Promise.all.
await inside a for...of when order matters:
async function processInOrder(items) {
for (const item of items) {
await processItem(item); // must be sequential
}
}
Use for...of (not forEach) when you need sequential execution.
forEach does not await:
// ❌ Doesn't wait
items.forEach(async item => {
await processItem(item); // this runs later
});
console.log('Done'); // prints before items are processed
// ✅ Waits
for (const item of items) {
await processItem(item);
}
console.log('Done');
forEach ignores the return value, so await inside it does nothing useful.
Returning values:
async function getValue() {
const x = await Promise.resolve(10);
return x * 2; // wrapped in Promise.resolve(20)
}
getValue().then(v => console.log(v));
// [ 20 ]
Returning a Promise:
async function getValue() {
return Promise.resolve(42); // Promise is flattened
}
getValue().then(v => console.log(v));
// [ 42 ]
Async functions unwrap returned Promises — you get the resolved value.
await in conditions:
async function check() {
if (await isLoggedIn()) {
return await getProfile();
}
return null;
}
await works anywhere inside an async function — conditions, loops, expressions.
await in expressions:
async function sum() {
const total = (await getA()) + (await getB());
return total;
}
Top-level await (ES modules only):
// In an .mjs file or <script type="module">
const data = await fetch('/api').then(r => r.json());
console.log(data);
In Node.js, works in .mjs or package.json with "type": "module".
Async function returning nothing:
async function noReturn() {
await something();
// returns Promise<void>
}
noReturn().then(() => console.log('Done'));
// [ Done ]
Nested async functions:
async function outer() {
const inner = async () => {
return await fetch('/data');
};
return await inner();
}
Async functions can be nested freely.
The await precedence trap:
// ❌ Wrong — await binds to fetch(...).then(...)
const data = await fetch('/data').then(r => r.json());
// ✅ Same thing, but clearer
const res = await fetch('/data');
const data = await res.json();
await has low precedence but only applies to the immediately following expression. When in doubt, break it into two lines.
Complete example — fetching a user and their posts:
async function getUserWithPosts(id) {
const userRes = await fetch(`/users/${id}`);
const user = await userRes.json();
const postsRes = await fetch(`/users/${id}/posts`);
const posts = await postsRes.json();
return { user, posts };
}
getUserWithPosts(1).then(({ user, posts }) => {
console.log(user.name);
console.log(posts.length);
});
c – Error handling with async/await
Async/await makes error handling simpler — you use plain try/catch, just like synchronous code.
await throws on rejection:
async function run() {
try {
const res = await fetch('/bad-url');
const data = await res.json();
} catch (err) {
console.log('Caught:', err.message);
}
}
run();
// [ Caught: Failed to fetch ]
Any rejected Promise — or any throw — becomes an exception inside the try block.
try/catch/finally all work:
async function run() {
showSpinner();
try {
const data = await fetchData();
return data;
} catch (err) {
console.error('Failed:', err.message);
return null;
} finally {
hideSpinner(); // always runs
}
}
Catching specific errors:
async function run() {
try {
const data = await fetchData();
} catch (err) {
if (err instanceof TypeError) {
console.log('Type problem:', err.message);
} else if (err instanceof Error) {
console.log('Generic error:', err.message);
}
}
}
Returning errors instead of throwing:
async function tryFetch(url) {
try {
const res = await fetch(url);
return { ok: true, data: await res.json() };
} catch (err) {
return { ok: false, error: err.message };
}
}
const result = await tryFetch('/api');
if (result.ok) {
console.log(result.data);
} else {
console.log('Error:', result.error);
}
This pattern avoids try/catch at every call site.
Re-throwing errors:
async function load() {
try {
return await fetchData();
} catch (err) {
console.error('Debug: failed', err);
throw err; // let the caller decide
}
}
await on a rejected Promise without catch:
async function run() {
await Promise.reject(new Error('unhandled'));
}
run(); // ❌ unhandled rejection
Always wrap in try/catch or attach .catch() at the call site.
Combining async/await with .catch():
const data = await fetchData().catch(err => {
console.error(err);
return null;
});
You can mix .catch() on individual Promises with try/catch for the whole function.
Error handling in parallel:
async function loadAll() {
try {
const results = await Promise.all([a(), b(), c()]);
return results;
} catch (err) {
console.log('One failed:', err.message);
return null;
}
}
Promise.all rejects with the first failure — one try/catch handles it.
Handling partial failures:
async function loadPartial() {
const results = await Promise.allSettled([a(), b(), c()]);
const ok = results.filter(r => r.status === 'fulfilled').map(r => r.value);
const failed = results.filter(r => r.status === 'rejected').map(r => r.reason);
return { ok, failed };
}
Use allSettled when you want to know what succeeded and what failed.
Retry logic with async/await:
async function retry(fn, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await fn();
} catch (err) {
if (i === attempts - 1) throw err;
console.log(`Attempt ${i + 1} failed, retrying...`);
}
}
}
await retry(() => fetch('/flaky'));
Timeout pattern with async/await:
function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
);
return Promise.race([promise, timeout]);
}
try {
const data = await withTimeout(fetch('/slow'), 5000);
} catch (err) {
console.log(err.message);
}
// [ Timeout ]
The key insight — async/await + try/catch = sync-style error handling:
// Sync
try {
const data = parseJson(text);
} catch (err) {
console.error(err);
}
// Async
try {
const data = await fetchJson(url);
} catch (err) {
console.error(err);
}
Same shape, same mental model. That’s the payoff of async/await.
Unhandled rejections — the trap:
// ❌ Floating Promise — no catch
async function run() {
fetchData(); // forgot await and .catch
}
// ✅ Handled
async function run() {
try {
await fetchData();
} catch (err) {
console.error(err);
}
}
// ✅ Or with .catch()
async function run() {
fetchData().catch(err => console.error(err));
}
Every Promise chain must end in .catch() or be inside a try/catch with await.
Complete Example Session
// ============================================
// PART 1: BASIC ASYNC
// ============================================
async function greet() {
return 'Hello';
}
greet().then(v => console.log(v));
// [ Hello ]
// ============================================
// PART 2: BASIC AWAIT
// ============================================
async function run() {
const value = await Promise.resolve(42);
console.log(value);
}
run();
// [ 42 ]
// ============================================
// PART 3: AWAIT ON NON-PROMISE
// ============================================
async function run() {
const a = await 42;
const b = await 'hi';
console.log(a, b);
}
run();
// [ 42 hi ]
// ============================================
// PART 4: ASYNC RETURNS PROMISE
// ============================================
async function getValue() {
return 42;
}
console.log(getValue());
// [ Promise { 42 } ]
getValue().then(v => console.log(v));
// [ 42 ]
// ============================================
// PART 5: THROW IN ASYNC
// ============================================
async function fails() {
throw new Error('boom');
}
fails().catch(err => console.log(err.message));
// [ boom ]
// ============================================
// PART 6: TRY/CATCH
// ============================================
async function run() {
try {
const res = await Promise.reject(new Error('network'));
} catch (err) {
console.log('Caught:', err.message);
}
}
run();
// [ Caught: network ]
// ============================================
// PART 7: TRY/CATCH/FINALLY
// ============================================
async function run() {
try {
await Promise.resolve('ok');
console.log('Try');
} catch (err) {
console.log('Catch');
} finally {
console.log('Finally');
}
}
run();
// [ Try ]
// [ Finally ]
// ============================================
// PART 8: SEQUENTIAL
// ============================================
async function sequential() {
const a = await Promise.resolve(1);
const b = await Promise.resolve(a + 1);
const c = await Promise.resolve(b + 1);
return c;
}
sequential().then(v => console.log(v));
// [ 3 ]
// ============================================
// PART 9: PARALLEL WITH PROMISE.ALL
// ============================================
async function parallel() {
const [a, b, c] = await Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
]);
return [a, b, c];
}
parallel().then(v => console.log(v));
// [ [ 1, 2, 3 ] ]
// ============================================
// PART 10: AWAIT IN A LOOP
// ============================================
async function loop() {
const results = [];
for (const x of [1, 2, 3]) {
results.push(await Promise.resolve(x * 10));
}
return results;
}
loop().then(v => console.log(v));
// [ [ 10, 20, 30 ] ]
// ============================================
// PART 11: PARALLEL IN A LOOP
// ============================================
async function parallelLoop() {
return Promise.all([1, 2, 3].map(x => Promise.resolve(x * 10)));
}
parallelLoop().then(v => console.log(v));
// [ [ 10, 20, 30 ] ]
// ============================================
// PART 12: FOREACH DOESN'T AWAIT
// ============================================
async function badLoop() {
[1, 2, 3].forEach(async x => {
await Promise.resolve(x);
console.log('Processed', x);
});
console.log('Done');
}
badLoop();
// [ Done ]
// [ Processed 1 ]
// [ Processed 2 ]
// [ Processed 3 ]
// ❌ Order is wrong
// ============================================
// PART 13: FOR...OF DOES AWAIT
// ============================================
async function goodLoop() {
for (const x of [1, 2, 3]) {
await Promise.resolve(x);
console.log('Processed', x);
}
console.log('Done');
}
goodLoop();
// [ Processed 1 ]
// [ Processed 2 ]
// [ Processed 3 ]
// [ Done ]
// ✅ Order is correct
// ============================================
// PART 14: ASYNC ARROW FUNCTION
// ============================================
const fetchData = async () => {
return await Promise.resolve('data');
};
fetchData().then(v => console.log(v));
// [ data ]
// ============================================
// PART 15: ASYNC METHOD
// ============================================
const api = {
async getUser(id) {
return { id, name: 'Alice' };
}
};
api.getUser(1).then(u => console.log(u));
// [ { id: 1, name: 'Alice' } ]
// ============================================
// PART 16: ASYNC CLASS METHOD
// ============================================
class Service {
async fetchUser(id) {
return await Promise.resolve({ id, name: 'Alice' });
}
}
new Service().fetchUser(1).then(u => console.log(u.name));
// [ Alice ]
// ============================================
// PART 17: IIFE
// ============================================
(async () => {
const data = await Promise.resolve('from IIFE');
console.log(data);
})();
// [ from IIFE ]
// ============================================
// PART 18: RETRY PATTERN
// ============================================
async function retry(fn, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await fn();
} catch (err) {
if (i === attempts - 1) throw err;
console.log(`Attempt ${i + 1} failed`);
}
}
}
let count = 0;
retry(async () => {
count++;
if (count < 3) throw new Error('fail');
return 'success';
}).then(v => console.log(v));
// [ Attempt 1 failed ]
// [ Attempt 2 failed ]
// [ success ]
// ============================================
// PART 19: TIMEOUT
// ============================================
function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
);
return Promise.race([promise, timeout]);
}
async function run() {
try {
await withTimeout(
new Promise(r => setTimeout(() => r('slow'), 2000)),
100
);
} catch (err) {
console.log(err.message);
}
}
run();
// [ Timeout ]
// ============================================
// PART 20: FULL SCRIPT
// ============================================
async function fetchData43() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return data;
}
fetchData43().then(data => console.log(data));
async function run43() {
try {
const result = await fetchData43();
console.log(result);
} catch (err) {
console.error('Failed:', err.message);
} finally {
console.log('Done');
}
}
run43();
async function sequential43() {
const a = await Promise.resolve(1);
const b = await Promise.resolve(a + 1);
return Promise.resolve(b + 1);
}
async function parallel43() {
const [a, b] = await Promise.all([
Promise.resolve(1),
Promise.resolve(2)
]);
return [a, b];
}
sequential43().then(v => console.log(v));
parallel43().then(v => console.log(v));
Quick Reference
async/await Basics
| Syntax | Meaning |
|---|---|
async function fn() {} | Returns a Promise |
await promise | Pauses until settled |
async () => {} | Async arrow function |
async method() {} | Async method |
(async () => {})() | Async IIFE |
async Rules
| Rule | Details |
|---|---|
| Always returns a Promise | Even for plain returns |
| Throws become rejections | Inside the async function |
| Can return Promises | They’re unwrapped |
await only inside async | Else SyntaxError |
await Rules
| Rule | Details |
|---|---|
| Works on any value | Non-Promises resolve instantly |
| Throws on rejection | Use try/catch |
| Pauses only the function | Other code keeps running |
| Low precedence | Break lines when chaining |
Sequential vs Parallel
| Pattern | Code |
|---|---|
| Sequential | const a = await f(); const b = await g(); |
| Parallel | const [a, b] = await Promise.all([f(), g()]); |
| Loop (ordered) | for (const x of arr) await f(x); |
| Loop (parallel) | await Promise.all(arr.map(x => f(x))); |
Error Handling
| Pattern | Code |
|---|---|
| try/catch | try { await f(); } catch (e) {} |
| try/catch/finally | try {} catch {} finally {} |
| Return error | return { ok: false, error } |
| Re-throw | catch (e) { throw e; } |
.catch() on Promise | await f().catch(...) |
| allSettled | const r = await Promise.allSettled(arr) |
Common Async Patterns
| Pattern | Description |
|---|---|
| Sequential | Each step depends on previous |
| Parallel | Independent steps |
| Timeout | Promise.race with timer |
| Retry | Loop with try/catch |
| Fallback | Catch and provide default |
| Batching | Promise.all in chunks |
| Concurrency limit | Batch + parallel |
async vs .then()
| Aspect | async/await | .then() |
|---|---|---|
| Readability | Sync-like | Chain-based |
| Error handling | try/catch | .catch() |
| Debugging | Better stack | Compressed |
| Loops | Native | Awkward |
| Conditionals | Native | Harder |
| Top-level | ES modules | Works |
Pitfalls
| Pitfall | Fix |
|---|---|
Missing await | Add await |
forEach with async | Use for...of |
| Await in loop | Use Promise.all |
| No try/catch | Add one |
await outside async | Move into function |
| Floating Promises | Always .catch() |
Best Practices
✅ Do This:
// Always handle errors
async function run() {
try { await f(); } catch (e) { log(e); }
} // ✅
// Use Promise.all for parallel
const [a, b] = await Promise.all([f(), g()]); // ✅
// Use for...of for sequential loops
for (const x of arr) await f(x); // ✅
// Use async arrow functions for callbacks
items.map(async x => await f(x)); // ✅ with Promise.all
// Return values directly
async function f() {
return await g(); // ✅
}
// Use allSettled for partial failures
const r = await Promise.allSettled(arr); // ✅
// Wrap floating Promises
void fetchData().catch(log); // ✅
// Use top-level await in modules
const data = await fetch('/api'); // ✅ in .mjs
❌ Don’t Do This:
// Don't forget await
const data = fetch('/x'); // ❌ Promise, not data
const data = await fetch('/x'); // ✅
// Don't use forEach with async
arr.forEach(async x => await f(x)); // ❌ doesn't wait
for (const x of arr) await f(x); // ✅
// Don't await in a loop when parallel is fine
for (const u of urls) await fetch(u); // ⚠️ sequential
await Promise.all(urls.map(fetch)); // ✅
// Don't swallow errors silently
try { await f(); } catch {} // ❌
// Don't await unnecessarily
const x = await 42; // ⚠️ works but odd
const x = 42; // ✅
// Don't mix callbacks and Promises
fs.readFile('x', async (err, data) => ...); // ❌
// Don't forget the async keyword
function f() { await g(); } // ❌ SyntaxError
// Don't rely on order in Promise.all
const [a, b] = await Promise.all([f(), g()]); // ✅ order by array
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
Missing await | Promise instead of value | Add await |
forEach with async | Loop doesn’t wait | for...of |
| Sequential in loop | Slow | Promise.all + map |
| No try/catch | Unhandled rejection | Wrap in try |
await outside async | SyntaxError | Move to async function |
| Floating Promise | Silent failure | .catch() or await |
| Awaiting non-Promise | Unnecessary | Skip await |
| Lost order in parallel | Race | Preserve array order |
Real-World Examples
1. Basic async function
async function greet() {
return 'Hello';
}
greet().then(v => console.log(v));
// [ Hello ]
2. Await a Promise
async function run() {
const value = await Promise.resolve(42);
console.log(value);
}
run();
// [ 42 ]
3. Await a non-Promise
async function run() {
const a = await 42;
console.log(a);
}
run();
// [ 42 ]
4. Async returns Promise
async function getValue() {
return 42;
}
getValue().then(v => console.log(v));
// [ 42 ]
5. Throw in async
async function fails() {
throw new Error('boom');
}
fails().catch(err => console.log(err.message));
// [ boom ]
6. try/catch
async function run() {
try {
await Promise.reject(new Error('network'));
} catch (err) {
console.log('Caught:', err.message);
}
}
run();
// [ Caught: network ]
7. try/catch/finally
async function run() {
try {
await Promise.resolve('ok');
console.log('Try');
} catch (err) {
console.log('Catch');
} finally {
console.log('Finally');
}
}
run();
// [ Try ]
// [ Finally ]
8. Sequential
async function sequential() {
const a = await Promise.resolve(1);
const b = await Promise.resolve(a + 1);
const c = await Promise.resolve(b + 1);
return c;
}
sequential().then(v => console.log(v));
// [ 3 ]
9. Parallel
async function parallel() {
const [a, b] = await Promise.all([
Promise.resolve(1),
Promise.resolve(2)
]);
return [a, b];
}
parallel().then(v => console.log(v));
// [ [ 1, 2 ] ]
10. Sequential loop
async function loop() {
const results = [];
for (const x of [1, 2, 3]) {
results.push(await Promise.resolve(x * 10));
}
return results;
}
loop().then(v => console.log(v));
// [ [ 10, 20, 30 ] ]
11. Parallel loop
async function parallelLoop() {
return Promise.all([1, 2, 3].map(x => Promise.resolve(x * 10)));
}
parallelLoop().then(v => console.log(v));
// [ [ 10, 20, 30 ] ]
12. Async arrow
const fetchData = async () => {
return await Promise.resolve('data');
};
fetchData().then(v => console.log(v));
// [ data ]
13. Async method
const api = {
async getUser(id) {
return { id, name: 'Alice' };
}
};
api.getUser(1).then(u => console.log(u));
// [ { id: 1, name: 'Alice' } ]
14. Async class method
class Service {
async fetchUser(id) {
return await Promise.resolve({ id, name: 'Alice' });
}
}
new Service().fetchUser(1).then(u => console.log(u.name));
// [ Alice ]
15. Async IIFE
(async () => {
const data = await Promise.resolve('from IIFE');
console.log(data);
})();
// [ from IIFE ]
16. Retry pattern
async function retry(fn, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await fn();
} catch (err) {
if (i === attempts - 1) throw err;
}
}
}
17. Timeout pattern
function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
);
return Promise.race([promise, timeout]);
}
async function run() {
try {
await withTimeout(new Promise(r => setTimeout(() => r('slow'), 2000)), 100);
} catch (err) {
console.log(err.message);
}
}
run();
// [ Timeout ]
18. Sequential file processing
async function processFiles(files) {
for (const file of files) {
await processFile(file);
}
}
19. Parallel data loading
async function loadDashboard(userId) {
const [user, orders, messages] = await Promise.all([
fetch(`/users/${userId}`).then(r => r.json()),
fetch(`/users/${userId}/orders`).then(r => r.json()),
fetch(`/users/${userId}/messages`).then(r => r.json())
]);
return { user, orders, messages };
}
20. Full Script
async function fetchData43() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return data;
}
fetchData43().then(data => console.log(data));
async function run43() {
try {
const result = await fetchData43();
console.log(result);
} catch (err) {
console.error('Failed:', err.message);
} finally {
console.log('Done');
}
}
run43();
const p1 = fetchData43();
const p2 = fetchData43();
const [a, b] = await Promise.all([p1, p2]);
async function sequential43() {
const a = await Promise.resolve(1);
const b = await Promise.resolve(a + 1);
return Promise.resolve(b + 1);
}
async function parallel43() {
const [a, b] = await Promise.all([
Promise.resolve(1),
Promise.resolve(2)
]);
return [a, b];
}
Visual: async/await Flow
┌──────────────────────────────────────────────┐
│ async function run() { │
│ console.log('start'); │
│ const data = await fetchData(); │
│ console.log('got:', data); │
│ return data; │
│ } │
│ │
│ Caller: │
│ run(); │
│ console.log('after call'); │
│ │
│ Order: │
│ 1. start │
│ 2. after call ← caller continues │
│ 3. got: data ← resumes after await │
│ │
│ await pauses ONLY the async function, │
│ not the caller. │
│ │
└──────────────────────────────────────────────┘
Visual: Sequential vs Parallel
┌──────────────────────────────────────────────┐
│ Sequential │
│ │
│ await a() ──────► a done │
│ await b() ──────► b done │
│ await c() ──────► c done │
│ │
│ Total: sum of times │
│ │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ Parallel │
│ │
│ await Promise.all([a(), b(), c()]) │
│ │
│ a() ────────────► │
│ b() ────────────► │
│ c() ────────────► │
│ │ │
│ └──► all done │
│ │
│ Total: max of times │
│ │
└──────────────────────────────────────────────┘
Visual: Error Handling
┌──────────────────────────────────────────────┐
│ try { │
│ const data = await fetchData(); │
│ // runs if resolved │
│ } catch (err) { │
│ // runs if rejected OR throws │
│ } finally { │
│ // always runs │
│ } │
│ │
│ Same shape as synchronous try/catch. │
│ │
└──────────────────────────────────────────────┘
Summary
| Concept | Syntax | Example |
|---|---|---|
| Async function | async function fn() {} | async function run() {} |
| Async arrow | async () => {} | const f = async () => {} |
| Async method | async method() {} | async fetch() {} |
| Async IIFE | (async () => {})() | Run at top level |
| Await | await promise | const x = await f() |
| Await non-Promise | await 42 | Resolves instantly |
| Return | return value | Wrapped in Promise |
| Throw | throw err | Rejects the Promise |
| try/catch | try { await f() } catch (e) {} | Handle errors |
| Sequential | await a; await b; | One at a time |
| Parallel | await Promise.all([a, b]) | All at once |
| Loop (ordered) | for (const x of arr) await f(x) | Sequential |
| Loop (parallel) | await Promise.all(arr.map(f)) | Concurrent |
| Retry | Loop with try/catch | Re-attempt |
| Timeout | Promise.race with timer | Fail fast |
Key takeaways:
asyncmarks a function as returning a Promise — alwaysawaitpauses the async function until a Promise settles and returns its valueawaitthrows on rejection — wrap intry/catchawaitonly pauses the current function — other code keeps running- Use
try/catch/finally— same shape as sync code - Sequential:
awaitone after another; parallel:await Promise.all - Don’t use
forEachwith async — it doesn’t wait; usefor...oformap+Promise.all - Returning a Promise from async unwraps it — you get the resolved value
awaiton non-Promises resolves immediately — safe but usually unnecessary- Top-level
awaitworks in ES modules and modern Node - Always handle errors — unhandled rejections crash or warn
- Master async/await and Promises become readable
Remember: async/await is Promises with better syntax. Mark a function async, write await in front of any Promise, handle errors with try/catch. Use Promise.all for parallel, for...of for sequential. Never forget await. Never use forEach with async. Always catch errors. Master async/await, and asynchronous JavaScript stops being scary — it just looks like regular code.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!