Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building a Custom Promise.all from Scratch

Tech 1

How Promise.all Works

Promise.all takes an array of Promise instances and returns a new Promise. When all input promises resolve successfully, the returned promise resolves with an array of results in the same order as the inputs. If any single promise rejects, the entire operation fails immediately, returning that rejection reason.

Basic Behavier Example

const p1 = Promise.resolve('first');
const p2 = Promise.resolve('second');
const p3 = Promise.reject('failed');

// Successful case - resolves with result array
Promise.all([p1, p2]).then(results => {
  console.log(results); // ['first', 'second']
});

// Failed case - immediately rejects with first rejection
Promise.all([p1, p3, p2]).catch(error => {
  console.log(error); // 'failed'
});

Implementing Promise.all

Here's a custom implementation that captures the core behavior:

function promiseAll(promises) {
  return new Promise((resolve, reject) => {
    const outputs = [];
    const totalPromises = promises.length;
    let completedCount = 0;

    if (totalPromises === 0) {
      resolve(outputs);
      return;
    }

    promises.forEach((item, index) => {
      if (item && typeof item.then === 'function') {
        item.then(
          value => {
            outputs[index] = value;
            completedCount++;
            if (completedCount === totalPromises) {
              resolve(outputs);
            }
          },
          reason => {
            reject(reason);
          }
        );
      } else {
        outputs[index] = item;
        completedCount++;
        if (completedCount === totalPromises) {
          resolve(outputs);
        }
      }
    });
  });
}

Testing the Implementation

const promiseA = Promise.resolve(42);
const promiseB = new Promise((_, reject) => setTimeout(() => reject('error'), 100));
const promiseC = Promise.resolve(99);

promiseAll([promiseA, promiseC]).then(values => {
  console.log(values); // [42, 99]
});

promiseAll([promiseA, promiseB, promiseC]).catch(err => {
  console.log(err); // 'error'
});

promiseAll([]).then(values => {
  console.log(values); // []
});

Key Implementation Details

Input Validation: The function checks if each item has a .then method to determine if it's a Promise. Non-Promise values are handled by wrapping them directly into the result array.

Short-Circuit on Rejection: Using the second argument of .then() for rejection hnadling ensures immediate rejection when any Promise fails.

Order Preservation: Results are assigned using the original array index, maintaining input order regardless of resolution timing.

Empty Array Handling: An edge case check returns an immediately resolved Promise with an empty array when no inputs are prvoided.

Counter Mechanism: A completion counter tracks resolved promises and triggers the final resolution only when all promises have been processed.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.