JavaScript async flow tool • 2026 standards
.then() and .catch(). Visualizes execution flow and error handling.
| Step | Method | Status | Time | Value |
|---|
| Step | Function | Input | Output | Duration |
|---|
A promise chain is a sequence of asynchronous operations connected using .then(), .catch(), and .finally() methods. Each method returns a new promise, allowing you to chain operations together. The chain executes sequentially, with each step waiting for the previous one to complete before proceeding.
Promise chains follow a specific execution pattern:
Where:
Errors in promise chains propagate to the next available .catch() handler:
.catch() can return new values to continue chain.then() handlerswindow.onunhandledrejection for global error handling.catch() in every chain.then() callbacksWhat are the three possible states of a JavaScript Promise?
The answer is A) Pending, Resolved, Rejected. These are the three fundamental states of a JavaScript Promise. A promise starts in the 'pending' state and eventually transitions to either 'fulfilled' (resolved) or 'rejected'. Once settled, a promise cannot change states again, making them immutable after resolution.
Understanding promise states is fundamental to working with asynchronous JavaScript. The immutability aspect is crucial - once a promise is resolved or rejected, it cannot transition to another state. This guarantee enables reliable chaining and error handling. The pending state represents the intermediate phase while the async operation is in progress.
Promise: Object representing eventual completion of async operation
Pending: Initial state, operation ongoing
Resolved/Fulfilled: Operation completed successfully
Rejected: Operation failed
• Promises can only transition from pending to settled
• Settled promises are immutable
• Each promise has exactly one state at any time
• Remember: Pending → Fulfilled OR Rejected (never both)
• Use Promise.state for debugging (non-standard)
• Chain promises for sequential operations
• Assuming promises can change state after settling
• Not understanding immutability of settled promises
• Confusing promise states with UI loading states
Explain how errors propagate through a promise chain and what happens to subsequent .then() handlers when an error occurs.
Error Propagation: When an error occurs in a promise chain, it skips all subsequent .then() handlers and jumps directly to the next available .catch() handler.
Skipping Behavior: If a promise rejects or throws an error in a .then() callback, all following .then() handlers are skipped.
Recovery: A .catch() handler can return a new value to recover from the error and continue the chain.
Unhandled Errors: If no .catch() handler exists, the promise rejection becomes unhandled.
This propagation mechanism is similar to exception handling in synchronous code. The chain continues to skip handlers until it finds an appropriate error handler. This allows for centralized error handling and prevents errors from affecting operations that shouldn't depend on the failed operation.
Error Propagation: Automatic forwarding of errors to error handlers
Unhandled Rejection: Rejected promise without error handler
Error Recovery: Handling errors to continue chain execution
• Errors skip subsequent .then() handlers
• Errors jump to next .catch() handler
• .catch() can return values to resume chain
• Place .catch() at end of chain for general error handling
• Use specific .catch() for targeted error handling
• Always handle rejections to prevent unhandled errors
• Forgetting to add .catch() handlers
• Placing .catch() in wrong location in chain
• Not understanding that .then() can throw errors too
A web application makes three sequential API calls: get user profile, get user preferences, and get user dashboard data. Each call depends on the previous one. If the first call fails, what happens to the subsequent calls? How would you modify the chain to handle this efficiently?
Default Behavior: If the first API call fails, the entire chain stops. The second and third calls never execute because the chain breaks at the first failure.
Optimized Approach:
1. Add error handling after each critical step: .catch() after each API call
2. Provide fallback values: .catch(() => defaultPreferences)
3. Use Promise.all() if calls don't depend on each other
4. Implement retry logic for transient failures
Result: The chain continues with fallback values or alternative paths, providing graceful degradation.
This scenario demonstrates the importance of defensive programming in promise chains. Rather than letting a single failure break the entire flow, we implement fallback mechanisms. This approach ensures users still receive some functionality even when parts of the system fail, improving resilience and user experience.
Graceful Degradation: System continues to function despite partial failures
Fallback Values: Default data used when primary source fails
Defensive Programming: Anticipating and handling potential failures
• Sequential dependencies mean early failure stops entire chain
• Fallbacks allow continuation after failures
• Parallel execution is faster when dependencies aren't required
• Use Promise.all() for independent parallel operations
• Implement circuit breakers for failing services
• Cache responses to reduce dependency on external calls
• Not considering cascade failures in dependent chains
• Not implementing fallback strategies
• Treating all API calls as equally critical
Compare the advantages and disadvantages of using promise chains (.then()) versus async/await syntax for handling the same sequence of asynchronous operations. When would you choose one over the other?
Promise Chains Advantages:
• Functional composition approach
• Easy to pipe transformations
• Better for library-level code
• Can be more efficient for simple operations
Async/Await Advantages:
• Synchronous-looking code
• Easier error handling with try/catch
• Better for complex conditional logic
• More readable for complex sequences
When to Choose:
• Use chains for simple data transformations
• Use async/await for complex business logic
• Use chains in functional programming contexts
• Use async/await for better debugging experience
Both approaches have their place in modern JavaScript development. The choice often depends on the complexity of the operation and team preferences. Promise chains excel at functional data transformations, while async/await shines in complex control flows. Understanding both allows developers to choose the most appropriate approach for each situation.
Functional Composition: Combining functions to build complex operations
Control Flow: Order and conditions of operation execution
Readability: How easily code can be understood
• Both approaches are functionally equivalent
• Choose based on complexity and team conventions
• Consider debugging and maintenance requirements
• Use chains for array-like transformations
• Use async/await for complex conditionals
• Hybrid approach can be effective
• Using only one approach for all situations
• Not considering team preferences
• Ignoring debugging implications
What is the difference between Promise.all() and Promise.race()?
The answer is A) all() waits for all to resolve, race() returns first settled. Promise.all() waits for all promises to resolve (or for any to reject) and returns an array of results. Promise.race() returns the result of whichever promise settles first, whether it resolves or rejects.
This distinction is crucial for parallel promise handling. Promise.all() is used when you need all operations to complete successfully, such as loading multiple resources simultaneously. Promise.race() is used when you want the fastest response, such as implementing timeout mechanisms or competing API endpoints.
Promise.all(): Waits for all promises to resolve or first rejection
Promise.race(): Returns first settled promise (resolve or reject)
Settled: Either resolved or rejected
• Promise.all() fails if any promise rejects
• Promise.race() completes with first result
• Both handle parallel execution differently
• Use Promise.all() for dependent parallel operations
• Use Promise.race() for timeout implementations
• Consider Promise.allSettled() to wait for all
• Confusing the behavior of all() and race()
• Not understanding failure conditions
• Using race() when all() is needed
Object representing eventual completion of async operation.
.then() → .catch() → .finally()
Sequential execution of async operations.
Always include .catch() handlers in promise chains.
Q: When should I use .then() vs async/await?
A: Use .then() for simple chains and functional transformations. Use async/await for complex logic with conditionals and loops. Both are valid approaches.
Q: Promise.all vs Promise.race?
A: Promise.all: Wait for ALL to complete. Promise.race: Return FIRST to complete. Use all() for dependent parallel ops, race() for timeouts.