Frontend Development 18 min read

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.

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); }
  }
}

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

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;
}

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

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);
  }
}

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.

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)); }); }

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.

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

login 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.