Understanding and Implementing JavaScript Promise: From Basic Construction to State Management

This article walks developers through building a functional JavaScript Promise from scratch, starting with a minimal callback list, adding chainable then calls, introducing a micro‑task delay to handle early resolves, and finally implementing state management so callbacks added after fulfillment still execute correctly.

vivo Internet Technology
vivo Internet Technology
vivo Internet Technology
Understanding and Implementing JavaScript Promise: From Basic Construction to State Management

Many developers learn the syntax of Promise without grasping its underlying mechanism. This article series explains Promise implementation step‑by‑step, using diagrams, examples, and animations to achieve a deep understanding.

The series is divided into four chapters:

Basic implementation of Promise

Chainable then calls

Adding an asynchronous delay mechanism

Introducing state management (pending, fulfilled, rejected)

1. Basic version

The simplest Promise stores callbacks in an array and invokes them when resolve is called.

//极简的实现
class Promise {
    callbacks = [];
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        this.callbacks.push(onFulfilled);
    }
    _resolve(value) {
        this.callbacks.forEach(fn => fn(value));
    }
}

//Promise应用
let p = new Promise(resolve => {
    setTimeout(() => {
        console.log('done');
        resolve('5秒');
    }, 5000);
}).then(tip => {
    console.log(tip);
});

This code shows how then registers a callback that runs after the asynchronous operation finishes.

2. Chainable then

To enable chaining, then returns the Promise instance itself.

//极简的实现+链式调用
class Promise {
    callbacks = [];
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        this.callbacks.push(onFulfilled);
        return this; // enable chaining
    }
    _resolve(value) {
        this.callbacks.forEach(fn => fn(value));
    }
}
let p = new Promise(resolve => {
    setTimeout(() => {
        console.log('done');
        resolve('5秒');
    }, 5000);
}).then(tip => {
    console.log('then1', tip);
}).then(tip => {
    console.log('then2', tip);
});

Now multiple then calls can be written in a single statement.

3. Adding an asynchronous delay (micro‑task queue)

When resolve runs before any then registration, callbacks are missed. Wrapping the callback execution in setTimeout defers it to the end of the task queue, guaranteeing that all then handlers are already registered.

//极简的实现+链式调用+延迟机制
class Promise {
    callbacks = [];
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        this.callbacks.push(onFulfilled);
        return this;
    }
    _resolve(value) {
        setTimeout(() => {
            this.callbacks.forEach(fn => fn(value));
        });
    }
}

With this change, even synchronous resolves trigger the callbacks after the current call stack.

Example of a synchronous resolve that previously lost then callbacks:

//同步执行了resolve
let p = new Promise(resolve => {
    console.log('同步执行');
    resolve('同步执行');
}).then(tip => {
    console.log('then1', tip);
}).then(tip => {
    console.log('then2', tip);
});

setTimeout(() => {
    p.then(tip => {
        console.log('then3', tip);
    });
});

After adding the delay, then1 and then2 are printed, but then3 still does not run because it is added after the promise is already fulfilled.

4. Introducing state management

To solve the remaining issue, the Promise tracks its state ( pending, fulfilled, rejected) and stores the resolved value. When then is called after fulfillment, the callback is executed immediately with the stored value.

//极简的实现+链式调用+延迟机制+状态
class Promise {
    callbacks = [];
    state = 'pending'; // 增加状态
    value = null;      // 保存结果
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        if (this.state === 'pending') {
            this.callbacks.push(onFulfilled);
        } else {
            onFulfilled(this.value);
        }
        return this;
    }
    _resolve(value) {
        this.state = 'fulfilled'; // 改变状态
        this.value = value;        // 保存结果
        this.callbacks.forEach(fn => fn(value));
    }
}

With state handling, callbacks added after resolution are still executed, completing a functional Promise implementation.

The article also includes diagrams illustrating the flow of each version and notes that only the fulfilled branch is implemented so far; future chapters will add rejected handling.

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.

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