手写Promise

手写代码

function Promise(executor) {
  const self = this;

  self.state = 'pending';
  self.data = undefined;
  self.resolvedCb = [];
  self.rejectedCb = [];

  function resolve(value) {
    if (value instanceof Promise) {
      return value.then(resolve, reject);
    }
    setTimeout(function () {
      if (self.state !== 'pending') return;
      self.state = 'resolve';
      self.data = value;
      for (const iterator of self.resolvedCb) {
        iterator(value);
      }
    });
  }

  function reject(reason) {
    setTimeout(function () {
      if (self.state !== 'pending') return;
      self.state = 'reject';
      self.data = reason;
      for (const iterator of self.rejectedCb) {
        iterator(reason);
      }
    });
  }

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

Promise.prototype.then = function (resolvedCb, rejectedCb) {
  const self = this;
  resolvedCb =
    typeof resolvedCb === 'function'
      ? resolvedCb
      : function (value) {
          return value;
        };
  rejectedCb =
    typeof rejectedCb === 'function'
      ? rejectedCb
      : function (reason) {
          throw reason;
        };
  let promise = null;
  return (promise = new Promise((resolve, reject) => {
    // pending
    if (self.state === 'pending') {
      self.resolvedCb.push(function (value) {
        try {
          const data = resolvedCb(value);
          resolvePromise(promise, data, resolve, reject);
        } catch (error) {
          reject(error);
        }
      });
      self.rejectedCb.push(function (reason) {
        try {
          const data = rejectedCb(reason);
          resolvePromise(promise, data, resolve, reject);
        } catch (error) {
          reject(error);
        }
      });
    }

    // resolve;
    if (self.state === 'resolve') {
      setTimeout(function () {
        try {
          const data = resolvedCb(self.data);
          resolvePromise(promise, data, resolve, reject);
        } catch (error) {
          reject(error);
        }
      });
    }

    // reject;
    if (self.state === 'reject') {
      setTimeout(function () {
        try {
          const data = rejectedCb(self.data);
          resolvePromise(promise, data, resolve, reject);
        } catch (error) {
          reject(error);
        }
      });
    }
  }));
};

Promise.prototype.catch = function (cb) {
  return this.then(null, cb);
};

function resolvePromise(promise2, x, resolve, reject) {
  var then;
  var thenCalledOrThrow = false;

  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise!'));
  }

  if (x instanceof Promise) {
    if (x.state === 'pending') {
      //because x could resolved by a Promise Object
      x.then(function (v) {
        resolvePromise(promise2, v, resolve, reject);
      }, reject);
    } else {
      //but if it is resolved, it will never resolved by a Promise Object but a static value;
      x.then(resolve, reject);
    }
    return;
  }

  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      then = x.then; //because x.then could be a getter
      if (typeof then === 'function') {
        then.call(
          x,
          function rs(y) {
            if (thenCalledOrThrow) return;
            thenCalledOrThrow = true;
            return resolvePromise(promise2, y, resolve, reject);
          },
          function rj(r) {
            if (thenCalledOrThrow) return;
            thenCalledOrThrow = true;
            return reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (thenCalledOrThrow) return;
      thenCalledOrThrow = true;
      return reject(e);
    }
  } else {
    resolve(x);
  }
}

// 测试工具 promises-aplus-tests
Promise.deferred = Promise.defer = function () {
  var dfd = {};
  dfd.promise = new Promise(function (resolve, reject) {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};

module.exports = Promise;

测试

npm i promises-aplus-tests -g
promises-aplus-tests promise.js

posted @   梦渊同学  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示