普通视图

发现新文章,点击刷新页面。
今天 — 2026年3月7日首页

从 0 手写 Promise:拆解 Promise 链式调用的实现原理

作者 龙猫不热
2026年3月6日 18:38

手写promise思路

1. promise本质

本质promise就是一个状态机 + 回调队列 + 链式调用规则

核心就3件事:

  1. 状态管理
  2. 回调存储执行
  3. then 链式调用

2. 第一步: 实现 Promise状态机

promise有三种状态

pending   初始状态
fulfilled 成功
rejected  失败

状态转换规则:

pending -> fulfilled
pending -> rejected

注意:

状态一旦改变就不能再变

所以需要:

this.status = "pending"
this.value = undefined
this.reason = undefined

3. 第二步: 实现resolve / reject

Promise 构造函数会接受一个 executor

new Promise((resolve,reject)=>{})

这个函数:

  • 立即执行
  • 会收到resolvereject

实现逻辑:

// value: resolve的值
// reason: reject的值, 失败原因

const resolve = (value)=>{
  if(this.status !== "pending") return
  this.status = "fulfilled"
  this.value = value
}

const reject = (reason)=>{
  if(this.status !== "pending") return
  this.status = "rejected"
  this.reason = reason
}

注意两点:

  1. 状态只能改一次
  2. 保留value / reason

4. 第三步: 实现then (核心)

Promise必须支持:

promise.then(onFulfilled, onRejected)

then 有三个行为:


4.1 情况1: Promise 已经fulfilled

立即执行 onFulfilled

但注意:

必须放到微任务

queueMicrotask(()=>{
  onFulfilled(this.value)
})

4.2 情况2: Promise 已经rejected

执行onRejected

queueMicrotask(()=>{
  onRejected(this.reason)
})

4.3 情况3: Promise 还在 pending

这时候问题来了:

resolve 可能未来才执行

所以: 要把回调存起来

this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []

then 里:

// 保证回调可以正常使用
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
onRejected =
    typeof onRejected === "function"
    ? onRejected
: (r) => {
    throw r;
};


this.onFulfilledCallbacks.push(() => {
    queueMicrotask(() => {
        onFulfilled(this.value)
    });
});

this.onRejectedCallbacks.push(() => {
    queueMicrotask(() => {
        onFulfilled(this.value)
    });
});

等到 resolve / rejected时

this.onFulfilledCallbacks.forEach(fn=>fn());
或
this.onRejectedCallbacks.forEach(fn=>fn());

5. 第四步: then必须返回新的Promise

规范规定:

then 一定要返回一个新的 Promise
const promise2 = new MyPromise(...)
return promise2

因为Promise需要支持链式调用

promise
  .then()
  .then()
  .then()

6. 第五步: then 返回值决定下一个Promise

最难的部分

const x = onFulfilled(this.value)

然后:

promise2 的状态 = x 决定

规则

6.1 情况1: x是普通值

resolve(x)

例:

then(()=>100)

6.2 情况2: x是 promise

then(()=>Promise)

那就:

promise 跟随这个 Promise最后的执行状态

例:

then(()=>new Promise(...))

6.3 情况3: x是 thenable

thenable:

const obj = { then: function(){} };
// 或
function fn(){
    // ....
}

fn.prototype.then = function(){
    // ....
}

也要按照 Promise处理


7. 第六步:reslovePromise 算法

所以需要写一个 统一解析函数

resolvePromise(promise2,x,resolve,reject)

作用:

解析x的类型

步骤:

7.1 防止循环引用

if(promise2 === x){
 reject(new TypeError("循环引用"))
}

例:

p.then(() => p) // 会死循环

7.2 如果 x 是对象或函数

typeof x === 'object' || typeof x === 'function'

说明可能是 thenable。


7.3 取 then

then = x.then

7.4 如果then是函数

当做Promise处理:

then.call(x, resolve, reject)

使用call的原因是防止里面有this调用

const obj = {
    value: 111,
    then(){
        console.log(this.value);
    }
}

7.5 如果then 不是函数

说明只是普通对象, 直接resolve:

resolve(x)

7.6 called锁

Promise规范规定

resolve / reject 只能调用一次

所以:

let called = false;

8. 第七步: 为什么要微任务

Promise 规范规定:

then 回调必须是异步执行的

所以必须:

queueMicrotask: 传入一个回调函数, 将回调函数中的代码加入到微任务队列中执行
// https://developer.mozilla.org/zh-CN/docs/Web/API/Window/queueMicrotask

而不是同步:

例:

Promise.resolve(1)
console.log(2)

// 2
// 1

9. 完整代码:

实现顺序

1 实现 Promise 状态
2 实现 resolve / reject
3 executor 立即执行
4 then 方法
5 then 返回新 Promise
6 回调队列
7 resolvePromise 解析返回值
8 微任务

完整结构其实只有 三块

class MyPromise
    constructor
    then

resolvePromise
class MyPromise {
  constructor(executor) {
    // 初始状态
    this.status = "pending";
    // 成功的值
    this.value = undefined;
    // 失败的原因
    this.reason = undefined;

    // 存储成功和失败的回调函数
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      // 保证状态不可逆
      if (this.status !== "pending") return;
      this.status = "fulfilled";
      this.value = value;
      // 执行成功的回调函数
      this.onFulfilledCallbacks.forEach((callback) => callback());
    };

    const reject = (reason) => {
      // 保证状态不可逆
      if (this.status !== "pending") return;
      this.status = "rejected";
      this.reason = reason;
      // 执行失败的回调函数
      this.onRejectedCallbacks.forEach((callback) => callback());
    };

    // 执行 executor,并捕获异常
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (r) => {
            throw r;
          };

    // .then需要可以返回一个新的promise
    // 并且promise的状态是按照回调函数的结果来做的
    const promise2 = new MyPromise((resolve, reject) => {
      if (this.status === "fulfilled") {
        queueMicrotask(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      } else if (this.status === "rejected") {
        queueMicrotask(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      } else if (this.status === "pending") {
        // 将回调函数保存起来,等到状态改变的时候再执行
        onFulfilled &&
          this.onFulfilledCallbacks.push(() => {
            queueMicrotask(() => {
              try {
                const x = onFulfilled(this.value);
                resolvePromise(promise2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            });
          });
        onRejected &&
          this.onRejectedCallbacks.push(() => {
            queueMicrotask(() => {
              try {
                const x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            });
          });
      }
    });
    return promise2;
  }

  /**
   * 1. 首先需要判断x是否和promise2相等, 如果相等将会造成循环引用, 需要reject出去一个error
   * 2. 如果 x 不是对象 或 函数, 则说明是普通值, resolve出去即可
   * 3. 如果是对象/函数, 需要看属性/原型上是否有 `then` 函数, 只要有就当成 promise 来处理
   * 4. 如果是对象/函数, 但没有`then`函数 或 `then`不是函数, 则直接resolve出去即可
   *
   * @param {*} promise2 将要返回的promise实例
   * @param {*} x 回调函数的返回值
   * @param {*} resolve
   * @param {*} reject
   * @returns
   */
}

function resolvePromise(promise2, x, resolve, reject) {
  if (x == promise2) {
    reject(new TypeError("Chaining cycle detected for promise"));
    return;
  }

  // 因为null也是object, 所以组合判断下
  if ((typeof x === "object" && x !== null) || typeof x == "function") {
    // 到这里说明是对象/函数

    let then;
    // Promise 只能 resolve 或 reject 一次, 做个锁
    let called = false;
    // 获取 then放到 try...catch中, 防止找不到then属性报错
    try {
      then = x.then;

      // 如果是个函数, 调用它
      // called做锁, 避免多次调用resolve 或 reject
      // 并且递归调用resolvePromise, 处理then返回的值
      if (typeof then === "function") {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            // reject就不需要再递归调用了
            if (called) return;
            called = true;
            reject(r);
          },
        );
      } else {
        // then不是函数就直接 resolve出去
        resolve(x);
      }
    } catch (error) {
      // 这边也要判断一下,如果called已经被调用过了, 就不再调用
      if (called) return;
      called = true;
      reject(error);
    }
  } else {
    resolve(x);
  }
}
❌
❌