Implementing Promises in JavaScript: Specification, Code Walkthrough, and Interview Guide

This article explains the evolution of JavaScript asynchronous programming, details the Promise/A+ specification, provides step‑by‑step custom Promise implementations with full code examples, covers additional Promise methods, and offers interview questions and best‑practice tips for frontend developers.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Implementing Promises in JavaScript: Specification, Code Walkthrough, and Interview Guide

Introduction

JavaScript asynchronous programming has gone through four stages—Callback, Promise, Generator, and Async/Await. The article begins with a brief history and explains why Promise became the core abstraction for handling async operations.

Promise/A+ Specification

The Promise/A+ spec is broken into terminology, requirements, and cautions. The article highlights three key requirements: three states (pending, fulfilled/resolved, rejected), immutable state transitions, and the then method returning a new promise.

1. Promise has three states: pending , fulfilled (called resolved in the article), and rejected . 2. State can only change from pending to resolved or rejected . 3. Once a state is set it cannot change again.

Step‑by‑Step Implementation

A minimal class is introduced that stores status and data, defines resolve and reject functions, and executes the executor safely.

<code class="language-javascript">class Promise {
  status = 'pending';
  data = '';
  constructor(executor) {
    function resolve(value) { this.status = 'resolved'; this.data = value; }
    function reject(reason) { this.status = 'rejected'; this.data = reason; }
    try { executor(resolve, reject); } catch (e) { reject(e); }
  }
}
</code>

The then method is then expanded to handle default callbacks, asynchronous execution via setTimeout, and storage of callbacks when the promise is still pending.

<code class="language-javascript">then(onResolved, onRejected) {
  onResolved = typeof onResolved === 'function' ? onResolved : v => v;
  onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e; };
  let promise2 = new Promise((resolve, reject) => {
    if (this.status === 'resolved') {
      setTimeout(() => {
        try { const x = onResolved(this.data); this.resolvePromise(promise2, x, resolve, reject); }
        catch (e) { reject(e); }
      }, 0);
    }
    // similar handling for 'rejected' and 'pending' cases …
  });
  return promise2;
}
</code>

The crucial resolvePromise helper follows the full Promise/A+ algorithm, handling self‑resolution, thenables, and error propagation.

<code class="language-javascript">resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) return reject(new TypeError('Chaining cycle detected'));
  if (x instanceof Promise) {
    if (x.status === 'pending') x.then(y => this.resolvePromise(promise2, y, resolve, reject), reject);
    else x.then(resolve, reject);
    return;
  }
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    let called = false;
    try {
      const then = x.then;
      if (typeof then === 'function') {
        then.call(x, y => { if (called) return; called = true; this.resolvePromise(promise2, y, resolve, reject); },
                  r => { if (called) return; called = true; reject(r); });
      } else { if (called) return; called = true; resolve(x); }
    } catch (e) { if (called) return; called = true; reject(e); }
  } else {
    resolve(x);
  }
}
</code>

Additional Promise Methods

Implementations for catch, finally, done, Promise.all, Promise.race, Promise.resolve, and Promise.reject are provided, each built on top of the core then logic.

<code class="language-javascript">catch(onRejected) { return this.then(null, onRejected); }
finally(fn) { return this.then(v => { fn(); return v; }, r => { fn(); throw r; }); }
static all(list) { return new Promise((resolve, reject) => { const results = []; let count = 0; list.forEach((p, i) => p.then(v => { results[i] = v; if (++count === list.length) resolve(results); }, reject)); }); }
</code>

Interview Guide

The article concludes with a set of common interview questions about Promise fundamentals, implementation details, event‑loop ordering, static methods, drawbacks, sequencing techniques, chain cancellation, error handling, and best practices, giving candidates concrete answers and code snippets.

Conclusion

By walking through the spec, implementing a fully‑featured Promise class, and summarising interview‑level knowledge, the article equips frontend developers with both practical coding skills and deeper conceptual understanding of asynchronous JavaScript.

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.

frontendJavaScriptAsynchronousinterviewimplementationPromise
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

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.