Promise chaining in Javascript - Time & Space Complexity
When using promise chaining, we want to know how the time to complete tasks grows as we add more steps.
We ask: How does adding more chained promises affect the total time?
Analyze the time complexity of the following code snippet.
const promiseChain = () => {
return new Promise(resolve => setTimeout(() => resolve(1), 1000))
.then(result => {
return new Promise(resolve => setTimeout(() => resolve(result + 1), 1000));
})
.then(result => {
return new Promise(resolve => setTimeout(() => resolve(result + 1), 1000));
});
};
This code creates a chain of promises where each step waits and then adds 1 to the result.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Each
thencallback runs one after another, waiting for the previous promise to finish. - How many times: The number of
thensteps in the chain determines how many times this happens.
Each chained promise waits for the previous one, so total time adds up with each step.
| Input Size (number of chained promises) | Approx. Total Time (ms) |
|---|---|
| 1 | 1000 |
| 2 | 2000 |
| 3 | 3000 |
Pattern observation: Total time grows linearly as you add more chained promises.
Time Complexity: O(n)
This means the total time grows directly in proportion to the number of chained promises.
[X] Wrong: "All promises run at the same time, so chaining does not add time."
[OK] Correct: In chaining, each promise waits for the previous one to finish, so times add up instead of running together.
Understanding how promise chains affect time helps you write efficient asynchronous code and explain your reasoning clearly.
What if we changed the chained promises to run in parallel using Promise.all? How would the time complexity change?
Practice
Solution
Step 1: Understand the purpose of promise chaining
Promise chaining is designed to run async tasks in sequence, where each step waits for the previous to finish and can use its result.Step 2: Compare options with the concept
Only Run asynchronous tasks one after another, passing results along correctly describes running async tasks one after another and passing results along.Final Answer:
Run asynchronous tasks one after another, passing results along -> Option CQuick Check:
Promise chaining = sequential async tasks [OK]
- Thinking promises run synchronously
- Believing chaining stops tasks immediately
- Confusing promise chaining with parallel execution
p1 and p2?Solution
Step 1: Understand promise chaining syntax
To chain promises, the first promise'sthenshould return the second promise function call, so it waits for it.Step 2: Analyze each option
p1.then(() => p2).then(result => console.log(result)); correctly returnsp2insidethen. p1.then(p2).then(result => console.log(result)); passesp2directly, which is incorrect. p1.then().then(p2).then(result => console.log(result)); has an emptythen()which is invalid. p1.then(result => p2).catch(console.log); usescatchprematurely and returnsp2incorrectly.Final Answer:
p1.then(() => p2).then(result => console.log(result)); -> Option BQuick Check:
Return next promise in then = correct chaining [OK]
- Passing promise directly to then instead of a function
- Leaving then() empty
- Misplacing catch before chain ends
Promise.resolve(5) .then(x => x * 2) .then(x => Promise.resolve(x + 3)) .then(console.log);
Solution
Step 1: Trace each then step
First,Promise.resolve(5)resolves with 5. Thenx => x * 2returns 10. Next,x => Promise.resolve(x + 3)returns a promise resolving to 13.Step 2: Understand final then output
The lastthen(console.log)logs the resolved value 13, not a promise object.Final Answer:
13 -> Option DQuick Check:
Promise chaining unwraps nested promises [OK]
- Thinking console.log prints a Promise object
- Ignoring that then unwraps promises
- Confusing multiplication and addition order
fetchData()
.then(data => processData(data))
.then(result => console.log(result))
.catch(error => console.error(error));
function processData(data) {
throw new Error('Processing failed');
}Solution
Step 1: Understand error throwing in promise chain
Throwing an error insideprocessDatacauses the promise to reject, which is caught by thecatchat the end.Step 2: Analyze catch placement and behavior
Thecatchat the end catches any error thrown in previousthencallbacks, including synchronous throws.Final Answer:
Error is caught by catch because thrown inside then chain -> Option AQuick Check:
Thrown errors in then are caught by catch [OK]
- Thinking synchronous errors are not caught
- Placing catch before then incorrectly
- Assuming missing return causes error
task1, task2, and task3 in order, where each depends on the previous result. Which code correctly chains them and catches any error once?Solution
Step 1: Understand dependency and error handling
Each task depends on the previous result, so eachthenmust pass the result to the next task function. A singlecatchat the end handles all errors.Step 2: Analyze each option
task1() .then(result1 => task2(result1)) .then(result2 => task3(result2)) .catch(error => console.error(error)); correctly chains tasks with result passing and one catch at the end. task1() .then(() => task2()) .then(() => task3()) .catch(error => console.error(error)); passes task2 and task3 without arguments, which may fail if they expect parameters. task1() .then(result1 => task2(result1)) .catch(error => console.error(error)) .then(result2 => task3(result2)); places catch too early, breaking the chain. task1() .catch(error => console.error(error)) .then(result1 => task2(result1)) .then(result2 => task3(result2)); places catch before then, so errors in later tasks are not caught.Final Answer:
task1().then(result1 => task2(result1)).then(result2 => task3(result2)).catch(error => console.error(error)); -> Option AQuick Check:
Chain with single catch at end and pass results [OK]
- Placing catch too early breaking chain
- Not passing results to dependent tasks
- Multiple catches causing partial error handling
Ready to prove it?
Pass the test and this pattern moves unknown
