Async Functions
The async keyword declares a function that always returns a Promise. It allows you to write async code that looks synchronous.
Basic Syntax
async function fetchData() {
return 'Hello'; // Automatically wrapped in Promise
}
fetchData().then(result => console.log(result)); // 'Hello'
Why Use Async?
Without async/await:
function getUser() {
return fetch('/api/user')
.then(response => response.json())
.then(user => {
return fetch(`/api/posts/${user.id}`);
})
.then(response => response.json())
.then(posts => {
console.log(posts);
});
}
With async/await:
async function getUser() {
const response = await fetch('/api/user');
const user = await response.json();
const postsResponse = await fetch(`/api/posts/${user.id}`);
const posts = await postsResponse.json();
console.log(posts);
}
Arrow Functions
const getData = async () => {
const data = await fetch('/api/data');
return data.json();
};
Top-Level Await
// In ES modules, you can use await at the top level
const response = await fetch('/api/config');
const config = await response.json();
export default config;
Await Syntax
The await keyword pauses the async function execution until the Promise settles.
How Await Works
async function example() {
console.log('Start');
const result = await Promise.resolve('done');
// Execution pauses here until promise resolves
console.log(result); // 'done'
console.log('End');
}
example();
// Output:
// Start
// done
// End
Await with Real Promises
async function fetchUserData() {
// Await pauses until fetch completes
const response = await fetch('/api/user');
// Check response
if (!response.ok) {
throw new Error('Network response was not ok');
}
// Await pauses until JSON parsing completes
const user = await response.json();
return user;
}
Parallel Operations
// BAD - sequential (slower)
async function getData() {
const users = await fetch('/api/users');
const posts = await fetch('/api/posts'); // Waits for users first
return { users, posts };
}
// GOOD - parallel (faster)
async function getData() {
const [users, posts] = await Promise.all([
fetch('/api/users'),
fetch('/api/posts')
]);
return { users, posts };
}
Await in Loops
// Sequential processing
async function processItems(items) {
const results = [];
for (const item of items) {
const result = await processItem(item);
results.push(result);
}
return results;
}
// Parallel processing
async function processItemsParallel(items) {
return Promise.all(items.map(item => processItem(item)));
}
Error Handling with try/catch
Async/await uses try/catch for error handling, which is more intuitive than .catch() chains.
Basic try/catch
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch failed:', error);
throw error; // Re-throw or handle
}
}
Multiple Error Points
async function complexOperation() {
let user;
let posts;
try {
user = await fetchUser();
} catch (error) {
console.error('User fetch failed:', error);
user = defaultUser;
}
try {
posts = await fetchPosts(user.id);
} catch (error) {
console.error('Posts fetch failed:', error);
posts = [];
}
return { user, posts };
}
Finally Block
async function loadData() {
showLoading();
try {
const data = await fetchData();
renderData(data);
} catch (error) {
showError(error);
} finally {
hideLoading(); // Always runs
}
}
Error Handling Patterns
// Pattern 1: Throw on error
async function getData() {
const response = await fetch('/api/data');
if (!response.ok) throw new Error('Failed');
return response.json();
}
// Pattern 2: Return null on error
async function getDataSafe() {
try {
const response = await fetch('/api/data');
if (!response.ok) return null;
return response.json();
} catch {
return null;
}
}
// Pattern 3: Tuple pattern
async function getDataTuple() {
try {
const response = await fetch('/api/data');
if (!response.ok) return [null, new Error('Failed')];
const data = await response.json();
return [data, null];
} catch (error) {
return [null, error];
}
}
// Usage
const [data, error] = await getDataTuple();
if (error) handleError(error);
Practice Problems
Create a reusable React component implementing Async / Await. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for Async / Await using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize Async / Await for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. What does an async function always return?
2. What does the await keyword do?
3. How do you handle errors in async/await?
4. What is wrong with this code? ```javascript async function getData() { const users = await fetch('/api/users'); const posts = await fetch('/api/posts'); } ```
Flashcards
Question
What is async/await?
Click to reveal answer
Answer
Syntax for working with Promises. async declares a function that returns a Promise. await pauses until a Promise settles.
Question
What does an async function return?
Click to reveal answer
Answer
Always returns a Promise. Return values are wrapped in Promise.resolve().
Question
How to run promises in parallel with async/await?
Click to reveal answer
Answer
Use Promise.all(): const [a, b] = await Promise.all([promiseA, promiseB]);
Question
Can you use await at the top level?
Click to reveal answer
Answer
Yes, in ES modules. Also in async IIFE: (async () => { await ... })()
Question
What is Async / Await?
Click to reveal answer
Answer
Async / Await is a key concept in frontend development.
Revision Notes
Key Takeaways
- 1.Async functions always return Promises
- 2.Await pauses execution until the Promise settles
- 3.Use try/catch for error handling in async functions
- 4.Use Promise.all() for parallel async operations
- 5.Async/await makes Promise-based code more readable
Interview Tips
- •Explain the difference between sequential and parallel async operations
- •Be able to convert Promise chains to async/await syntax
- •Discuss error handling strategies with try/catch
- •Know when to use Promise.all() vs sequential awaits
Cheat Sheet
Async/Await Cheat Sheet
Basic Syntax
async function name() {
const result = await promise;
return result;
}
Error Handling
try {
const data = await fetchData();
} catch (error) {
console.error(error);
} finally {
cleanup();
}
Parallel Operations
const [a, b] = await Promise.all([
fetchA(),
fetchB()
]);
Key Points
- async functions always return Promises
- await pauses until Promise settles
- Use try/catch for errors
- Use Promise.all() for parallel operations