CrackFrontendCF
Resources
Practice
CrackFrontend

Your guide to mastering frontend interviews

Resources

LibraryPracticeDonate

Company

About UsContact

Legal

Privacy PolicyTerms of Service

Built with ❀️ by Tushar Khanna

CrackFrontendCF
Resources
Practice

🎯 Promise.all() Implementation

Promise.all waits for all promises to resolve and returns their results as an array. Rejects immediately if any promise fails.

Interview Importance: πŸ”΄ Critical β€” Implementing is one of the most common JavaScript interview questions. Tests understanding of promises, async handling, and edge cases. -- 1️⃣ What is Promise.all? takes an iterable (usually an array) of promises and returns a single promise that: Resolves when ALL input promises resolve -returns array of results in order Rejects immediately when ANY promise rejects -returns the first rejection reason Visual Behavior -- 2️⃣ Why Use Promise.all? Use Cases Without Promise.all Sequential: slow One-by-one Complex chaining Manual tracking Performance Benefit -- 3️⃣ How Promise.all Works β€” Implementation Basic Implementation πŸ” Dry Run: All Promises Resolve πŸ” Dry Run: One Promise Rejects -- 4️⃣ Key Implementation Details Why ? accepts any iterable, not just arrays: Why ? Handles non-promise values (normalizes input): Why Store by Index ()? Preserves order regardless of resolution order: Why Counter Instead of ? Sparse arrays can have length without actual values: -- 5️⃣ Edge Cases Behavior Resolves immediately with Wrapped in All work together Rejects immediately First rejection wins Edge Case Implementation Test -- 6️⃣ Complete Production Implementation -- 7️⃣ Related Promise Methods Comparison Resolves When Use Case ALL resolve Need all results Never FIRST settles Timeout/fastest ALL reject Comparison Example -- 8️⃣ Common Interview Questions Q1: Implement Promise.all from scratch Answer: See Section 3 or Section 6. Q2: What's the difference between Promise.all and Promise.allSettled? Answer: : Fails fast on first rejection : Waits for all promises, never rejects, returns status for each Q3: Does Promise.all execute promises in parallel? Answer: Yes, but with a nuance. The promises start executing when created, not when passed to . just waits for them all: Q4: What happens if you pass a non-iterable to Promise.all? Answer: It throws a : Q5: How would you implement a version with a concurrency limit? Answer: -- 9️⃣ Common Pitfalls Pitfall 1: Not Handling Rejections Pitfall 2: Creating Promises Inside Promise.all Pitfall 3: Expecting Order of Execution -- πŸ”Ÿ Time & Space Complexity Complexity O(n) O(n) O(max(durations)) -- Summary Description Wait for all promises to resolve Resolution Fails fast on first rejection Empty array Automatically wrapped | Key Takeaways 1. Parallel execution β€” all promises run concurrently 2. Order preserved β€” results match input order, not resolution order 3. Fail fast β€” one rejection fails everything 4. Use β€” when you need all outcomes regardless of failures 5. Always handle rejections β€” use try/catch or -- πŸ“š Further Reading MDN: Promise.all JavaScript.info: Promise API -- <!-quiz-start --Q1: What happens when one promise in Promise.all rejects? [ ] It waits for all promises to complete and returns partial results [x] It immediately rejects with the first rejection reason [ ] It filters out the rejected promise and returns remaining results [ ] It replaces the rejected value with undefined Q2: Why do we store results by index () instead of using push? [ ] Push is slower than direct array assignment [ ] It prevents memory leaks [x] It preserves the order of results matching input order, regardless of resolution order [ ] It's required for TypeScript compatibility Q3: What does Promise.all return when passed an empty array? [ ] It throws a TypeError [ ] It returns a pending promise that never resolves [x] It resolves immediately with an empty array [] [ ] It rejects with "No promises provided" <!-quiz-end --
JavaScriptPromises
🎯 Promise.all() Implementation
hard
βœ… Promise.allSettled() Implementation
medium
🎯 Promise.any() Implementation
medium
πŸ›‘ Cancelable Promise Implementation
medium
πŸ”§ Custom Promise Class Implementation
hard
🏁 Promise.race() Implementation
medium
πŸ”„ Promise Retry Implementation
easy
πŸ“‹ Sequential Promise Execution
medium
1 of 8
LibraryJavaScriptPromises40 of 61

🎯 Promise.all() Implementation

jspromiseshard

Interview Importance: πŸ”΄ Critical β€” Implementing Promise.all is one of the most common JavaScript interview questions. Tests understanding of promises, async handling, and edge cases.


1️⃣ What is Promise.all?

Promise.all takes an iterable (usually an array) of promises and returns a single promise that:

  • Resolves when ALL input promises resolve -> returns array of results in order
  • Rejects immediately when ANY promise rejects -> returns the first rejection reason
Input:  [Promise1, Promise2, Promise3]
                v
           Promise.all()
                v
Output: Promise<[result1, result2, result3]>

Visual Behavior

Scenario 1: All Resolve
---------------------------------------------------------
Promise 1: --------●------------------------------------> resolves "A" at 100ms
Promise 2: ------------------●--------------------------> resolves "B" at 200ms
Promise 3: ----------------------------●----------------> resolves "C" at 300ms
                                       v
Promise.all: --------------------------●----------------> resolves ["A", "B", "C"]
                                    (at 300ms - waits for slowest)

Scenario 2: One Rejects
---------------------------------------------------------
Promise 1: --------●------------------------------------> resolves "A" at 100ms
Promise 2: --------------βœ—------------------------------> REJECTS "error" at 150ms
Promise 3: ----------------------------●----------------> (ignored - would resolve at 300ms)
                         v
Promise.all: ------------βœ—------------------------------> REJECTS "error"
                      (at 150ms - fails fast)

2️⃣ Why Use Promise.all?

Use Cases

ScenarioWithout Promise.allWith Promise.all
Fetch multiple APIsSequential: slowParallel: fast
Load multiple resourcesOne-by-oneAll at once
Validate multiple conditionsComplex chainingClean and readable
Batch operationsManual trackingAutomatic handling

Performance Benefit

// ❌ Sequential - takes ~600ms (100 + 200 + 300)
const a = await fetchA();  // 100ms
const b = await fetchB();  // 200ms
const c = await fetchC();  // 300ms

// βœ… Parallel - takes ~300ms (max of all)
const [a, b, c] = await Promise.all([
  fetchA(),  // 100ms -+
  fetchB(),  // 200ms -+--> All run in parallel
  fetchC()   // 300ms -+
]);

3️⃣ How Promise.all Works β€” Implementation

Basic Implementation

function promiseAll(iterable) {
  return new Promise((resolve, reject) => {
    // Convert iterable to array (handles Sets, generators, etc.)
    const promises = Array.from(iterable);
    const results = [];
    let resolvedCount = 0;

    // Edge case: empty array resolves immediately
    if (promises.length === 0) {
      return resolve([]);
    }

    promises.forEach((promise, index) => {
      // Wrap in Promise.resolve to handle non-promise values
      Promise.resolve(promise)
        .then((value) => {
          // Store result at correct index (preserves order)
          results[index] = value;
          resolvedCount++;

          // All resolved? Return results
          if (resolvedCount === promises.length) {
            resolve(results);
          }
        })
        .catch((error) => {
          // First rejection fails the entire Promise.all
          reject(error);
        });
    });
  });
}

πŸ” Dry Run: All Promises Resolve

promiseAll([
  Promise.resolve(1),           // Resolves immediately
  new Promise(r => setTimeout(() => r(2), 100)),  // Resolves at 100ms
  Promise.resolve(3)            // Resolves immediately
]).then(console.log);
Initial State:
---------------------------------------------------------
promises = [Promise(1), Promise(2), Promise(3)]
results = []
resolvedCount = 0

Step 1: Process index 0 - Promise.resolve(1)
---------------------------------------------------------
Promise resolves immediately with value: 1
results[0] = 1    ->  results = [1, empty, empty]
resolvedCount = 1
Check: 1 === 3?   ->  No, continue waiting

Step 2: Process index 2 - Promise.resolve(3)
---------------------------------------------------------
Promise resolves immediately with value: 3
results[2] = 3    ->  results = [1, empty, 3]
resolvedCount = 2
Check: 2 === 3?   ->  No, continue waiting

Step 3: Process index 1 - setTimeout Promise (at t=100ms)
---------------------------------------------------------
Promise resolves with value: 2
results[1] = 2    ->  results = [1, 2, 3]
resolvedCount = 3
Check: 3 === 3?   ->  Yes! resolve(results)

Output: [1, 2, 3]

Key Insight: Results are in ORDER [1, 2, 3] even though
             Promise at index 1 resolved LAST!

πŸ” Dry Run: One Promise Rejects

promiseAll([
  Promise.resolve(1),
  Promise.reject('Error!'),
  new Promise(r => setTimeout(() => r(3), 100))
]).catch(console.log);
Step 1: Process index 0 - Promise.resolve(1)
---------------------------------------------------------
resolves with 1
results = [1, empty, empty]
resolvedCount = 1

Step 2: Process index 1 - Promise.reject('Error!')
---------------------------------------------------------
REJECTS with 'Error!'
-> reject('Error!') is called
-> Promise.all IMMEDIATELY rejects

Step 3: Index 2's setTimeout would resolve at t=100ms
---------------------------------------------------------
But Promise.all already rejected!
(Promise still runs to completion, but result is ignored)

Output: 'Error!'

4️⃣ Key Implementation Details

Why Array.from(iterable)?

Promise.all accepts any iterable, not just arrays:

// Works with Set
Promise.all(new Set([Promise.resolve(1), Promise.resolve(2)]));

// Works with generators
function* gen() {
  yield Promise.resolve(1);
  yield Promise.resolve(2);
}
Promise.all(gen());

// Works with strings (each char becomes a resolved promise)
Promise.all('abc');  // Resolves to ['a', 'b', 'c']

Why Promise.resolve(promise)?

Handles non-promise values (normalizes input):

Promise.all([1, 2, Promise.resolve(3)]);
// Without Promise.resolve wrapper: 1 and 2 would fail
// With wrapper: Resolves to [1, 2, 3]

Why Store by Index (results[index] = value)?

Preserves order regardless of resolution order:

Promise.all([
  new Promise(r => setTimeout(() => r('slow'), 200)),  // index 0
  new Promise(r => setTimeout(() => r('fast'), 50))    // index 1
]);

// 'fast' resolves first, but results[1] = 'fast'
// 'slow' resolves second, results[0] = 'slow'
// Final result: ['slow', 'fast'] - ORDER PRESERVED!

Why Counter Instead of results.length?

Sparse arrays can have length without actual values:

const arr = [];
arr[5] = 'value';
console.log(arr.length);  // 6, but only 1 actual value!

// Our approach:
// results = [empty, empty, 3] has length 3
// But resolvedCount = 1 (accurate!)

5️⃣ Edge Cases

Edge CaseBehaviorExample
Empty arrayResolves immediately with []Promise.all([]) -> []
Non-promise valuesWrapped in Promise.resolve()Promise.all([1, 2]) -> [1, 2]
Mixed valuesAll work togetherPromise.all([1, Promise.resolve(2)]) -> [1, 2]
Already rejectedRejects immediatelyPromise.all([Promise.reject('x')]) -> rejects
Multiple rejectionsFirst rejection winsOnly first error returned

Edge Case Implementation Test

// Test 1: Empty array
promiseAll([]).then(r => console.log(r));  // []

// Test 2: Non-promises
promiseAll([1, 'two', { three: 3 }])
  .then(r => console.log(r));  // [1, 'two', { three: 3 }]

// Test 3: Null/undefined values
promiseAll([null, undefined, Promise.resolve(3)])
  .then(r => console.log(r));  // [null, undefined, 3]

// Test 4: All reject
promiseAll([
  Promise.reject('first'),
  Promise.reject('second')
]).catch(e => console.log(e));  // 'first' (first rejection wins)

6️⃣ Complete Production Implementation

function promiseAll(iterable) {
  return new Promise((resolve, reject) => {
    // Handle null/undefined
    if (iterable == null) {
      throw new TypeError('Argument is not iterable');
    }

    // Convert to array
    const promises = Array.from(iterable);
    const results = new Array(promises.length);
    let resolvedCount = 0;
    let rejected = false;

    // Empty iterable - resolve immediately
    if (promises.length === 0) {
      return resolve([]);
    }

    promises.forEach((promise, index) => {
      Promise.resolve(promise)
        .then((value) => {
          // Ignore if already rejected
          if (rejected) return;

          results[index] = value;
          resolvedCount++;

          if (resolvedCount === promises.length) {
            resolve(results);
          }
        })
        .catch((error) => {
          // Only reject once
          if (rejected) return;
          rejected = true;
          reject(error);
        });
    });
  });
}

7️⃣ Related Promise Methods Comparison

MethodResolves WhenRejects WhenUse Case
Promise.allALL resolveANY rejectsNeed all results
Promise.allSettledALL settleNeverNeed all outcomes
Promise.raceFIRST settlesFIRST rejectsTimeout/fastest
Promise.anyANY resolvesALL rejectFirst success

Comparison Example

const promises = [
  Promise.reject('error'),
  new Promise(r => setTimeout(() => r('slow'), 100)),
  Promise.resolve('fast')
];

Promise.all(promises)        // ❌ Rejects: 'error'
Promise.allSettled(promises) // βœ… [{status:'rejected'}, {status:'fulfilled',...}, ...]
Promise.race(promises)       // ❌ Rejects: 'error' (first to settle)
Promise.any(promises)        // βœ… Resolves: 'fast' (first to succeed)

8️⃣ Common Interview Questions

Q1: Implement Promise.all from scratch

Answer: See Section 3 or Section 6.

Q2: What's the difference between Promise.all and Promise.allSettled?

Answer:

  • Promise.all: Fails fast on first rejection
  • Promise.allSettled: Waits for all promises, never rejects, returns status for each
// Promise.all - ONE failure = entire operation fails
Promise.all([Promise.resolve(1), Promise.reject('fail')])
  .catch(e => console.log(e));  // 'fail'

// Promise.allSettled - Get results regardless of failures
Promise.allSettled([Promise.resolve(1), Promise.reject('fail')])
  .then(results => console.log(results));
  // [{status: 'fulfilled', value: 1}, {status: 'rejected', reason: 'fail'}]

Q3: Does Promise.all execute promises in parallel?

Answer: Yes, but with a nuance. The promises start executing when created, not when passed to Promise.all. Promise.all just waits for them all:

// These start immediately when created:
const p1 = fetchUser();   // Starts now
const p2 = fetchPosts();  // Starts now
const p3 = fetchComments(); // Starts now

// Promise.all just waits for all to complete
const results = await Promise.all([p1, p2, p3]);

Q4: What happens if you pass a non-iterable to Promise.all?

Answer: It throws a TypeError:

Promise.all(123);  // TypeError: 123 is not iterable
Promise.all(null); // TypeError: null is not iterable

Q5: How would you implement a version with a concurrency limit?

Answer:

async function promiseAllWithLimit(promises, limit) {
  const results = [];
  const executing = [];

  for (const [index, promise] of promises.entries()) {
    const p = Promise.resolve(promise).then(value => {
      results[index] = value;
    });

    executing.push(p);

    if (executing.length >= limit) {
      await Promise.race(executing);
      // Remove settled promises
      executing.splice(
        executing.findIndex(e => e === p), 1
      );
    }
  }

  await Promise.all(executing);
  return results;
}

9️⃣ Common Pitfalls

Pitfall 1: Not Handling Rejections

// ❌ BAD: Unhandled rejection if any promise fails
const results = await Promise.all([fetchA(), fetchB()]);

// βœ… GOOD: Always handle potential rejections
try {
  const results = await Promise.all([fetchA(), fetchB()]);
} catch (error) {
  console.error('One of the fetches failed:', error);
}

// βœ… ALTERNATIVE: Use Promise.allSettled for guaranteed results
const results = await Promise.allSettled([fetchA(), fetchB()]);

Pitfall 2: Creating Promises Inside Promise.all

// ❌ This is fine, but be aware promises start immediately
Promise.all([
  fetch('/api/1'),  // Starts immediately
  fetch('/api/2'),  // Starts immediately
]);

// ❌ BAD: Using async callbacks creates timing issues
Promise.all(
  ids.map(async id => {
    const data = await fetch(`/api/${id}`);
    return data.json();
  })
);

// βœ… GOOD: Be explicit about what you're doing
Promise.all(
  ids.map(id => fetch(`/api/${id}`).then(r => r.json()))
);

Pitfall 3: Expecting Order of Execution

// The execution order is NOT guaranteed
Promise.all([
  asyncOp1(),  // Might finish 3rd
  asyncOp2(),  // Might finish 1st
  asyncOp3()   // Might finish 2nd
]).then(([result1, result2, result3]) => {
  // But results ARE in input order!
  // result1 is from asyncOp1, regardless of when it finished
});

πŸ”Ÿ Time & Space Complexity

AspectComplexityExplanation
TimeO(n)Iterates through n promises once
SpaceO(n)Stores n results
ExecutionO(max(durations))Total time = slowest promise
// n = number of promises
// If promises take [100ms, 200ms, 50ms]:
// Total time β‰ˆ 200ms (not 350ms - parallel!)

Summary

ConceptDescription
Promise.allWait for all promises to resolve
ResolutionReturns array of results in input order
RejectionFails fast on first rejection
Empty arrayResolves immediately with []
Non-promisesAutomatically wrapped

Key Takeaways

  1. Parallel execution β€” all promises run concurrently
  2. Order preserved β€” results match input order, not resolution order
  3. Fail fast β€” one rejection fails everything
  4. Use Promise.allSettled β€” when you need all outcomes regardless of failures
  5. Always handle rejections β€” use try/catch or .catch()

πŸ“š Further Reading

  • MDN: Promise.all
  • JavaScript.info: Promise API

Quick Quiz

Test your understanding with 3 quick questions

Q1What happens when one promise in Promise.all rejects?
Q2Why do we store results by index (`results[index] = value`) instead of using push?
Q3What does Promise.all return when passed an empty array?

Continue Reading

CrackFrontend

Your guide to mastering frontend interviews

Resources

LibraryPracticeDonate

Company

About UsContact

Legal

Privacy PolicyTerms of Service

Built with ❀️ by Tushar Khanna