Promise 相关手写

Promise 相关手写


javascript promise 手写实现

Promise 手写代码

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MPromise {
  FULFILLED_CALLBACK_LIST = [];
  REJECTED_CALLBACK_LIST = [];
  constructor(fn) {
    this.status = PENDING;
    this.result = null;
    this.reason = null;
    try {
      fn(this.resolve.bind(this), this.reject.bind(this));
    } catch (e) {
      this.reject(e);
    }
  }
  resolve(value) {
    if (this.status === PENDING) {
      this.status = FULFILLED;
      this.result = value;
      this.FULFILLED_CALLBACK_LIST.forEach((cb) => {
        cb(this.result);
      });
    }
  }
  reject(value) {
    this.status = REJECTED;
    this.reason = value;
    this.REJECTED_CALLBACK_LIST.forEach((cb) => {
      cb(this.reason);
    });
  }
  then(onFulFilled, onRejected) {
    switch (this.status) {
      case FULFILLED: {
        const newPromise = new MPromise((resolve, reject) => {
          queueMicrotask(() => {
            try {
              if (typeof onFulFilled !== "function") {
                resolve(this.result);
              } else {
                let x = onFulFilled(this.result);
                resolvePromise(newPromise, x, resolve, reject);
              }
            } catch (e) {
              reject(e);
            }
          });
        });
        return newPromise;
      }
      case REJECTED: {
        const newPromise = new MPromise((resolve, reject) => {
          queueMicrotask(() => {
            try {
              if (typeof onRejected !== "function") {
                reject(this.reason);
              } else {
                let x = onRejected(this.reason);
                resolvePromise(newPromise, x, resolve, reject);
              }
            } catch (e) {
              reject(e);
            }
          });
        });
        return newPromise;
      }
      case PENDING: {
        //  一个Promise可以多次.then,当它状态还是pending的时候,需要把回调维护到数组里,等到状态改变时同时调用
        const newPromise = new MPromise((resolve, reject) => {
          this.FULFILLED_CALLBACK_LIST.push(() =>
            queueMicrotask(() => {
              try {
                if (typeof onFulFilled !== "function") {
                  resolve(this.result);
                } else {
                  let x = onFulFilled(this.result);
                  resolvePromise(newPromise, x, resolve, reject);
                }
              } catch (e) {
                reject(e);
              }
            })
          );
          this.REJECTED_CALLBACK_LIST.push(() =>
            queueMicrotask(() => {
              try {
                if (typeof onRejected !== "function") {
                  reject(this.reason);
                } else {
                  let x = onRejected(this.reason);
                  resolvePromise(newPromise, x, resolve, reject);
                }
              } catch (e) {
                reject(e);
              }
            })
          );
        });
        return newPromise;
      }
    }
  }
  // catch和finally方法不需要 也符合PromiseA+规范,这边写上是为了方便看这两个方法的手写实现
  catch(onRejected) {
    return this.then(undefined, onRejected);
  }
  finally(cb) {
    return this.then(cb, cb);
  }
}
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    throw new TypeError("循环引用");
  } else if (x instanceof MPromise) {
    x.then((y) => {
      resolvePromise(promise2, y, resolve, reject);
    }, reject);
  } else if ((typeof x === "object" && x !== null) || typeof x === "function") {
    let then = null;
    try {
      then = x.then;
    } catch (e) {
      return reject(e);
    }
    if (typeof then === "function") {
      // 如果then方法中 resolvePromise 和 rejectPromise 被同时调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
      let called = false;
      try {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          (e) => {
            if (called) return;
            called = true;
            reject(e);
          }
        );
      } catch (e) {
        if (called) return;
        called = true;
        reject(e);
      }
    } else {
      resolve(x);
    }
  } else {
    resolve(x);
  }
}

PromiseA+规范 测试

MPromise.deferred = function () {
  let result = {};
  result.promise = new MPromise((resolve, reject) => {
    result.resolve = resolve;
    result.reject = reject;
  });
  return result;
};

module.exports = MPromise;

npm i promises-aplus-tests -D
npx promises-aplus-tests MPromise.js

Promise 静态方法实现

Promise.resolve

const myPromiseResolve = (value) => {
  if (value instanceof Promise) {
    return value;
  } else if (
    value instanceof Object &&
    Reflect.ownKeys(value).includes("then") &&
    typeof value.then === "function"
  ) {
    return new Promise((resolve, reject) => {
      value.then(resolve, reject);
    });
  }
  return new Promise((r) => {
    r(value);
  });
};

测试

myPromiseResolve(new Promise((r) => r(1))).then(console.log); // 1
myPromiseResolve({
  then: (onFulFilled) => {
    onFulFilled(1);
  },
}).then(console.log); // 1
myPromiseResolve(1).then(console.log); // 1

Promise.reject

const myPromiseReject = (value) => {
  return new Promise((resolve, reject) => {
    reject(value);
  });
};

测试

myPromiseReject(1).then(null, console.log); // 1

Promise.prototype.catch & Promise.prototype.finally

catch(onRejected) {
  return this.then(undefined, onRejected);
}

finally(cb) {
  return this.then(cb, cb);
}

Promise.all

const myPromiseAll = (promises) => {
  return new Promise((resolve, reject) => {
    if (Array.isArray(promises)) {
      let result = [];
      let count = 0;
      if (promises.length === 0) {
        return resolve(promises);
      }
      promises.forEach((item, index) => {
        if (item instanceof Promise) {
          item.then(
            (res) => {
              count++;
              result[index] = res;
              if (count === promises.length) resolve(result);
            },
            (reason) => {
              reject(reason);
            }
          );
        } else {
          count++;
          result[index] = item;
          if (count === promises.length) resolve(result);
        }
      });
    } else {
      reject(new TypeError("非数组"));
    }
  });
};

测试

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "foo");
});

myPromiseAll([promise1, promise2, promise3]).then((values) => {
  console.log(values); //  [3, 42, 'foo']
});

Promise.allSettled

const myPromiseAllSettled = (promises) => {
  return new Promise((resolve, reject) => {
    if (Array.isArray(promises)) {
      let result = [];
      let count = 0;
      if (promises.length === 0) {
        return resolve(promises);
      }
      promises.forEach((item, index) => {
        // 非promise值,通过Promise.resolve转换为promise进行统一处理
        Promise.resolve(item).then(
          (res) => {
            count++;
            result[index] = {
              status: "fulfilled",
              value: res,
            };
            if (count === promises.length) resolve(result);
          },
          (reason) => {
            count++;
            result[index] = {
              status: "rejected",
              reason: reason,
            };
            if (count === promises.length) resolve(result);
          }
        );
      });
    } else {
      reject(new TypeError("非数组"));
    }
  });
};

测试

const p1 = Promise.resolve(3);
const p2 = new Promise((resolve, reject) => setTimeout(reject, 100, "foo"));
const p3 = 1;
const ps = [p1, p2, p3];

myPromiseAllSettled(ps).then((results) =>
  results.forEach((result) => console.log(result))
);
/*
{ status: 'fulfilled', value: 3 }
{ status: 'rejected', reason: 'foo' }
{ status: 'fulfilled', value: 1 }
*/

Promise.any

// Promise.any() 接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。
// 如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),
// 就返回一个失败的 promise 和AggregateError类型的实例,它是 Error 的一个子类,用于把单一的错误集合在一起。

const myPromiseAny = (promises) => {
  return new Promise((resolve, reject) => {
    if (Array.isArray(promises)) {
      let count = 0;
      let errors = [];
      if (promises.length === 0) {
        return reject(new Error("All promises were rejected"));
      }
      promises.forEach((item, index) => {
        Promise.resolve(item).then(
          (res) => {
            resolve(res);
          },
          (reason) => {
            count++;
            errors.push(reason);
            if (count === promises.length) reject(new Error(errors));
          }
        );
      });
    } else {
      reject(new TypeError("非数组"));
    }
  });
};

测试

const pErr = new Promise((resolve, reject) => {
  reject("总是失败");
});

const pSlow = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "最终完成");
});

const pFast = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "很快完成");
});

myPromiseAny([pErr, pSlow, pFast]).then((value) => {
  console.log(value); // 很快完成
});

const pErr1 = new Promise((resolve, reject) => {
  reject("总是失败");
});

const pErr2 = new Promise((resolve, reject) => {
  reject("总是失败");
});

const pErr3 = new Promise((resolve, reject) => {
  reject("总是失败");
});

myPromiseAny([pErr1, pErr2, pErr3]).catch((e) => {
  console.log(e); // [总是失败,总是失败,总是失败]
});

Promise.race

// Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
const myPromiseRace = (promises) => {
  return new Promise((resolve, reject) => {
    if (Array.isArray(promises)) {
      // 如果传入的迭代promises是空的,则返回的 promise 将永远等待。
      if (promises.length > 0) {
        promises.forEach((item) => {
          Promise.resolve(item).then(resolve, reject);
        });
      }
    } else {
      reject(new TypeError("非数组"));
    }
  });
};

测试

const p4 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "one");
});

const p5 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "two");
});

myPromiseRace([p4, p5]).then((value) => {
  console.log("p5 :>> ", value); // two
});

除了 catch 和 finally, 以上方法都属于 Promise 类上的静态方法,可以用 static 关键字挂在 MPromise 上 catch 和 finally 在 MPromise 类中实现了

参考链接

https://juejin.cn/post/7043758954496655397 https://juejin.cn/post/7044088065874198536

© 2025 Niko Xie