Creating Promises
A Promise is an object representing the eventual completion or failure of an async operation.
Promise States
- Pending: Initial state, neither fulfilled nor rejected
- Fulfilled: Operation completed successfully
- Rejected: Operation failed
Creating a Promise
const myPromise = new Promise((resolve, reject) => {
// Perform async operation
const success = true;
if (success) {
resolve('Operation completed!'); // Fulfilled
} else {
reject(new Error('Something went wrong')); // Rejected
}
});
// Using the Promise
myPromise
.then(result => console.log(result)) // 'Operation completed!'
.catch(error => console.error(error));
Practical Example
function fetchUser(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId > 0) {
resolve({ id: userId, name: 'John' });
} else {
reject(new Error('Invalid user ID'));
}
}, 1000);
});
}
fetchUser(1)
.then(user => console.log(user))
.catch(err => console.error(err));
Immediate Resolution
// Promise.resolve() - creates already fulfilled promise
const resolved = Promise.resolve('done');
// Promise.reject() - creates already rejected promise
const rejected = Promise.reject('error');
Promise Chaining
Promise chaining allows you to perform sequential async operations, avoiding callback hell.
Basic Chaining
fetchUser(1)
.then(user => {
console.log('User:', user);
return fetchPosts(user.id); // Return new promise
})
.then(posts => {
console.log('Posts:', posts);
return fetchComments(posts[0].id);
})
.then(comments => {
console.log('Comments:', comments);
})
.catch(err => {
console.error('Error in chain:', err);
});
Key Rules
- Each
.then()returns a new Promise - The value passed to the next
.then()is the resolved value .catch()handles errors from any previous.then()- Always return promises or values from
.then()
Common Mistake
// WRONG - breaking the chain
fetchUser(1)
.then(user => {
fetchPosts(user.id); // Missing return!
})
.then(posts => {
console.log(posts); // undefined!
});
// CORRECT
fetchUser(1)
.then(user => {
return fetchPosts(user.id); // Return the promise
})
.then(posts => {
console.log(posts); // Array of posts
});
Parallel Execution
// Running promises in parallel
Promise.all([
fetchUser(1),
fetchUser(2),
fetchUser(3)
]).then(([user1, user2, user3]) => {
console.log('All users:', user1, user2, user3);
});
Error Handling
Proper error handling is crucial for robust Promise-based code.
.catch() Method
fetchUser(1)
.then(user => fetchPosts(user.id))
.then(posts => processPosts(posts))
.catch(error => {
console.error('Error:', error.message);
// Handle error from any step in the chain
});
.finally() Method
fetchUser(1)
.then(user => console.log(user))
.catch(err => console.error(err))
.finally(() => {
console.log('Done!'); // Runs regardless of success/failure
hideLoadingSpinner();
});
Error Propagation
function step1() {
return Promise.resolve('step1');
}
function step2() {
throw new Error('Error in step2');
}
function step3() {
return Promise.resolve('step3');
}
step1()
.then(result => {
console.log(result); // 'step1'
return step2();
})
.then(result => {
console.log(result); // Skipped!
return step3();
})
.catch(err => {
console.error(err); // 'Error in step2'
});
Handling Multiple Errors
fetchUser(1)
.then(user => {
if (!user.name) {
throw new Error('Missing name');
}
return user;
})
.catch(error => {
if (error.message === 'User not found') {
return defaultUser; // Recover and continue
}
throw error; // Re-throw for other errors
});
Promise Combinators
Promise combinators help manage multiple promises together.
Promise.all()
Resolves when ALL promises resolve. Rejects if ANY rejects.
Promise.all([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
])
.then(([users, posts, comments]) => {
console.log('All data loaded');
})
.catch(error => {
console.error('One request failed:', error);
});
Promise.allSettled()
Resolves when ALL promises settle (fulfill or reject). Never rejects.
Promise.allSettled([
Promise.resolve('success'),
Promise.reject('failure'),
Promise.resolve('another success')
])
.then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('Value:', result.value);
} else {
console.log('Reason:', result.reason);
}
});
});
Promise.race()
Resolves/rejects with the FIRST settled promise.
Promise.race([
fetch('/api/fast'),
fetch('/api/slow'),
new Promise((_, reject) =>
setTimeout(() => reject('Timeout'), 5000)
)
])
.then(result => {
console.log('First response:', result);
})
.catch(error => {
console.log('Error or timeout:', error);
});
Promise.any()
Resolves with the FIRST fulfilled promise. Rejects if ALL reject.
Promise.any([
fetch('/api/primary'),
fetch('/api/backup1'),
fetch('/api/backup2')
])
.then(result => {
console.log('Got response from:', result.url);
})
.catch(errors => {
console.log('All failed:', errors);
});
Practice Problems
Create a reusable React component implementing Promises. 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 Promises using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize Promises 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 are the three states of a Promise?
2. What does Promise.all() do if one promise rejects?
3. What is the difference between .catch() and .finally()?
4. Which combinator never rejects?
Flashcards
Question
What is a Promise?
Click to reveal answer
Answer
An object representing the eventual completion or failure of an async operation. States: Pending, Fulfilled, Rejected.
Question
What does .then() return?
Click to reveal answer
Answer
A new Promise. If you return a value, it becomes the resolved value. If you return a Promise, the chain waits for it.
Question
Promise.all() vs Promise.allSettled()?
Click to reveal answer
Answer
Promise.all() rejects if any promise rejects. Promise.allSettled() always resolves with status of each promise.
Question
What is Promise.race()?
Click to reveal answer
Answer
Resolves or rejects with the first settled promise. Useful for timeout patterns.
Question
How do you handle errors in promise chains?
Click to reveal answer
Answer
Use .catch() at the end of the chain to handle errors from any previous .then().
Revision Notes
Key Takeaways
- 1.Promises represent eventual completion or failure of async operations
- 2.Promise chaining avoids callback hell
- 3..catch() at the end handles errors from any step
- 4.Promise.all() is for parallel operations that must all succeed
- 5.Promise.allSettled() is for when you want all results regardless of success
Interview Tips
- •Know the difference between Promise.all(), allSettled(), race(), and any()
- •Be able to write a Promise chain that properly handles errors
- •Explain how Promises relate to the event loop (microtasks)
- •Discuss when to use Promises vs callbacks vs async/await
Cheat Sheet
Promises Cheat Sheet
States
- Pending: Initial state
- Fulfilled: Operation succeeded
- Rejected: Operation failed
Creating
new Promise((resolve, reject) => {
if (success) resolve(value);
else reject(error);
});
Methods
.then()- Handle success.catch()- Handle error.finally()- Run regardless
Combinators
Promise.all()- All must succeedPromise.allSettled()- Wait for allPromise.race()- First to settlePromise.any()- First to succeed