Deep Dive into Implementing JavaScript Promise: Static Methods, resolve, reject, all & race

This article walks through a step‑by‑step implementation of JavaScript's Promise, covering prototype methods, static helpers like resolve, reject, all, and race, with detailed code examples, execution flow explanations, and a summary of the underlying observer pattern.

vivo Internet Technology
vivo Internet Technology
vivo Internet Technology
Deep Dive into Implementing JavaScript Promise: Static Methods, resolve, reject, all & race

Promise is a core solution for asynchronous programming in JavaScript, standardized in ES6. This series aims to help readers understand the inner workings of Promise by progressively implementing it, visualizing the process with diagrams, examples, and animations.

Prototype Method Implementation Recap

The previous sections built the prototype methods (then, catch, finally) and added state handling (pending, fulfilled, rejected) and result storage. The current implementation looks like this:

class Promise {
  callbacks = [];
  state = 'pending'; // increase state
  value = null; // store result
  constructor(fn) {
    fn(this._resolve.bind(this), this._reject.bind(this));
  }
  then(onFulfilled, onRejected) {
    return new Promise((resolve, reject) => {
      this._handle({
        onFulfilled: onFulfilled || null,
        onRejected: onRejected || null,
        resolve,
        reject
      });
    });
  }
  catch(onError) { return this.then(null, onError); }
  finally(onDone) {
    if (typeof onDone !== 'function') return this.then();
    let Promise = this.constructor;
    return this.then(
      value => Promise.resolve(onDone()).then(() => value),
      reason => Promise.resolve(onDone()).then(() => { throw reason })
    );
  }
  _handle(callback) {
    if (this.state === 'pending') { this.callbacks.push(callback); return; }
    let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected;
    if (!cb) { cb = this.state === 'fulfilled' ? callback.resolve : callback.reject; cb(this.value); return; }
    let ret;
    try { ret = cb(this.value); cb = this.state === 'fulfilled' ? callback.resolve : callback.reject; }
    catch (error) { ret = error; cb = callback.reject; }
    finally { cb(ret); }
  }
  _resolve(value) {
    if (value && (typeof value === 'object' || typeof value === 'function')) {
      var then = value.then;
      if (typeof then === 'function') { then.call(value, this._resolve.bind(this), this._reject.bind(this)); return; }
    }
    this.state = 'fulfilled'; // change state
    this.value = value; // save result
    this.callbacks.forEach(callback => this._handle(callback));
  }
  _reject(error) {
    this.state = 'rejected';
    this.value = error;
    this.callbacks.forEach(callback => this._handle(callback));
  }
}

Static Methods Overview

Beyond prototype methods, Promise provides static helpers: Promise.resolve, Promise.reject, Promise.all, and Promise.race. Their implementations follow similar patterns.

Promise.resolve & Promise.reject

Promise.resolve

wraps non‑Promise values into a resolved Promise. If the argument is already a Promise, it returns it unchanged. Example:

Promise.resolve('foo') // equivalent to new Promise(resolve => resolve('foo'))

When the argument is a thenable object, Promise.resolve adopts its state by calling its then method:

let thenable = { then: function(onFulfilled) { onFulfilled(42); } };
let p1 = Promise.resolve(thenable);
p1.then(value => console.log(value)); // 42

If the argument is a primitive or a non‑thenable object, a new resolved Promise is returned. Calling Promise.resolve() with no argument yields a Promise already resolved with undefined.

The source code for Promise.resolve:

static resolve(value) {
  if (value && value instanceof Promise) { return value; }
  else if (value && typeof value === 'object' && typeof value.then === 'function') {
    let then = value.then;
    return new Promise(resolve => { then(resolve); });
  } else if (value) {
    return new Promise(resolve => resolve(value));
  } else {
    return new Promise(resolve => resolve());
  }
}
Promise.reject

always returns a Promise in the rejected state, regardless of its argument.

Promise.all

Promise.all

accepts an array of Promises (or values) and resolves when every entry is fulfilled, returning an array of results in the same order:

const p1 = new Promise(resolve => setTimeout(() => resolve('p1'), 1000));
const p2 = new Promise(resolve => setTimeout(() => resolve('p2'), 5000));
Promise.all([p1, p2]).then(rets => console.log(rets)); // ['p1','p2']

Implementation:

static all(promises) {
  return new Promise((resolve, reject) => {
    let fulfilledCount = 0;
    const itemNum = promises.length;
    const rets = Array.from({ length: itemNum });
    promises.forEach((promise, index) => {
      Promise.resolve(promise).then(result => {
        fulfilledCount++;
        rets[index] = result;
        if (fulfilledCount === itemNum) { resolve(rets); }
      }, reason => reject(reason));
    });
  });
}

Promise.race

Promise.race

returns a Promise that settles as soon as any of the supplied Promises settles (fulfilled or rejected). Example:

const p1 = new Promise(resolve => setTimeout(() => resolve('p1'), 1000));
const p2 = new Promise(resolve => setTimeout(() => resolve('p2'), 5000));
Promise.race([p1, p2]).then(ret => console.log(ret)); // 'p1'

Implementation:

static race(promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      Promise.resolve(promises[i]).then(
        value => resolve(value),
        reason => reject(reason)
      );
    }
  });
}

Key Takeaways

The core of Promise relies on the observer pattern: then and catch register observers, while the internal state machine (pending → fulfilled/rejected) notifies them via resolve or reject. Understanding that then merely registers callbacks and the actual execution happens inside resolve clarifies the flow.

Although the presented implementation demonstrates the main ideas, it does not fully satisfy every requirement of the Promise/A+ specification.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptAsyncPromiseCodeExamplePromiseAllPromiseRaceStaticMethods
vivo Internet Technology
Written by

vivo Internet Technology

Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.