手写 Promise 源码

Promise

  1. 基本 Promise
    执行器
    resolve, reject, then(同步)
    resolve(异步,基于发布订阅)

  2. then 链式调用 p.then().then();

基本链式调用:在 then 里面返回 promise

需要考虑 then return 的是 promise 还是普通值
x 如果是 promise 则,需要考虑调用 resolve 还是 reject
x 如果是普通值, 则调用 resolve

一、创建 Promise 类

class Promise {
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECTED = "rejected";

  constructor(executor) {
    this.status = Promise.PENDING;
    this.value = undefined;
    this.reason = undefined;
  }

  then(onFulfilled, onRejected) {}
}

二、实现 resolve 和 reject

class Promise {
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECTED = "rejected";

  constructor(executor) {
    this.status = Promise.PENDING;
    this.value = undefined;
    this.reason = undefined;

    const resolve = (value) => {
      if (this.status === Promise.PENDING) {
        this.status = Promise.FULFILLED;
        this.value = value;
      }
    };
    const reject = (reason) => {
      if (this.status === Promise.PENDING) {
        this.status = Promise.REJECTED;
        this.reason = reason;
      }
    };

    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }

  then(onFulfilled, onRejected) {}
}

三、实现 then 方法

  1. 基础 then 方法(同步)
class Promise {
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECTED = "rejected";

  constructor(executor) {
    this.status = Promise.PENDING;
    this.value = undefined;
    this.reason = undefined;

    const resolve = (value) => {
      if (this.status === Promise.PENDING) {
        this.status = Promise.FULFILLED;
        this.value = value;
      }
    };
    const reject = (reason) => {
      if (this.status === Promise.PENDING) {
        this.status = Promise.REJECTED;
        this.reason = reason;
      }
    };

    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }

  then(onFulfilled, onRejected) {
    if (this.status === Promise.FULFILLED) {
      onFulfilled(this.value);
    }
    if (this.status === Promise.REJECTED) {
      onFulfilled(this.value);
    }
  }
}
  1. 异步 resolve 时,实现异步

基于发布订阅

class Promise {
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECTED = "rejected";

  constructor(executor) {
    this.status = Promise.PENDING;
    this.value = undefined;
    this.reason = undefined;

    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.status === Promise.PENDING) {
        this.status = Promise.FULFILLED;
        this.value = value;
        this.onResolvedCallbacks.forEach((fn) => fn());
      }
    };
    const reject = (reason) => {
      if (this.status === Promise.PENDING) {
        this.status = Promise.REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }

  then(onFulfilled, onRejected) {
    if (this.status === Promise.FULFILLED) {
      onFulfilled(this.value);
    }
    if (this.status === Promise.REJECTED) {
      onFulfilled(this.value);
    }
    if (this.status === Promise.PENDING) {
      this.onResolvedCallbacks.push(() => {
        onFulfilled(this.value);
      });
      this.onRejectedCallbacks.push(() => {
        onRejected(this.reason);
      });
    }
  }
}
  1. then 链式调用

then 链式调用 p.then().then();

then 函数中需要返回一个 promise

基本链式调用:在 then 里面返回 promise

需要考虑 then return 的是 promise 还是普通值
x 如果是 promise 则,需要考虑调用 resolve 还是 reject
x 如果是普通值, 则调用 resolve

// 利用 X 的值判断 promise2 是 resolve 还是 reject
function resolvePromise(promise2, x, resolve, reject) {
  // console.log(promise2, x, resolve, reject);

  // 考虑循环情况
  if (x === promise2) {
    reject(
      new TypeError(`TypeError: Chaining cycle detected for promise #<Promise>`)
    );
  }

  // 兼容其他 promise
  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    // 加锁,防止别人的 promise 调了成功后还是可以调成功!
    let called = false;

    // 取别人的 x(Promise), x.then 时可能会抛出异常,所以用 try...catch...
    try {
      let then = x.then;

      if (typeof then === "function") {
        // 这里不使用 x.then 而使用 then.call(x) 也是防止取 p.then 时可能会抛出异常
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolve(y);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        // x 可能是一个带有 then 属性的对象 { then: {} }
        resolve(x);
      }
    } catch (error) {
      if (called) return;
      called = true;
      reject(error);
    }
  } else {
    // 普通值,直接 resolve
    resolve(x);
  }
}

class Promise {
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECTED = "rejected";

  constructor(executor) {
    this.status = Promise.PENDING;
    this.value = undefined;
    this.reason = undefined;

    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.status === Promise.PENDING) {
        this.status = Promise.FULFILLED;
        this.value = value;
        this.onResolvedCallbacks.forEach((fn) => fn());
      }
    };
    const reject = (reason) => {
      if (this.status === Promise.PENDING) {
        this.status = Promise.REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value;

    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };

    let promise2 = new Promise((resolve, reject) => {
      if (this.status === Promise.FULFILLED) {
        // 为什么使用 setTimeout?
        // 使得 resolvePromise 中能够获取到 promise2
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);

            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      }

      if (this.status === Promise.REJECTED) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      }

      if (this.status === Promise.PENDING) {
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        });
      }
    });
    return promise2;
  }
}

resolvePromise(promise2, x, resolve, reject);

这个函数功能: 利用 x 的值判断 promise2 是 resolve 还是 reject

x === promise2 的判断主要针对下面这个情况

if (x === promise2) {
  reject(
    new TypeError(`TypeError: Chaining cycle detected for promise #<Promise>`)
  );
}
let promise = new Promise(() => {
  resolve(1);
}).then(() => {
  return promise;
});

let then = x.then;

这里为什么使用 try…catch…?

在获取别人的 Promise 时,可能不让获取 promise.then,
下面使用 then.call(x, ()=>{}, ()=>{}) 而不使用 x.then(()=>{}, ()=>{}) 同样是为了防止取用别人的 Promise 是不让获取 then 属性。

called

设置加锁,防止别人的 promise 不遵守 "状态改变后不可再修改"的承诺,可以多次修改状态

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值