【无标题】

实现一个自定义promise 并通过Promise/A+测试

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

function MyPromise(executor) {
  const self = this;
  self.value = null;
  self.error = null;
  self.status = PENDING;
  self.onFulfilledCallbacks = [];
  self.onRejectedCallbacks = [];

  function resolve(value) {
    if (value instanceof MyPromise) {
      return value.then(resolve, reject);
    }
    if (self.status === PENDING) {
      self.status = FULFILLED;
      self.value = value;
      self.onFulfilledCallbacks.forEach((callback) => callback(self.value));
    }
  }

  function reject(error) {
    if (self.status === PENDING) {
      self.status = REJECTED;
      self.error = error;
      self.onRejectedCallbacks.forEach((callback) => callback(self.error));
    }
  }

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

function resolvePromise(promise2, x, resolve, reject) {
  //2.3.1规范,避免循环引用
  if (promise2 === x) {
    return reject(new TypeError('Circular reference'));
  }
  let called = false;
  if (x != null && ((typeof x === 'object') || (typeof x === 'function'))) {
    try {
      // 是否是thenable对象(具有then方法的对象/函数)
      //2.3.3.1 将 then 赋为 x.then
      let then = x.then;
      if (typeof then === 'function') {
        //2.3.3.3 如果 then 是一个函数,以x为this调用then函数,且第一个参数是resolvePromise,第二个参数是rejectPromise
        then.call(x, y => {
          if (called) return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, error => {
          if (called) return;
          called = true;
          reject(error);
        })
      } else {
        //2.3.3.4 如果 then不是一个函数,则 以x为值fulfill promise。
        resolve(x);
      }
    } catch (e) {
      //2.3.3.2 如果在取x.then值时抛出了异常,则以这个异常做为原因将promise拒绝。
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

MyPromise.resolve = (val) => {
  return new MyPromise((resolve) => {
    resolve(val)
  })
}
MyPromise.reject = (err) => {
  return new MyPromise((resolve, reject) => {
    reject(err)
  })
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
  const self = this;
  let promise2;
  onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
  onRejected = typeof onRejected === "function" ? onRejected : error => {
    throw error
  };
  if (self.status === FULFILLED) {
    return promise2 = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        try {
          let x = onFulfilled(self.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      }, 0);
    })
  }
  if (self.status === REJECTED) {
    return promise2 = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        try {
          let x = onRejected(self.error);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      }, 0);
    });
  }
  if (self.status === PENDING) {
    return promise2 = new MyPromise((resolve, reject) => {
      self.onFulfilledCallbacks.push((value) => {
        setTimeout(()=>{
          try {
            let x = onFulfilled(value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        })
      });
      self.onRejectedCallbacks.push((error) => {
        setTimeout(()=>{
          try {
            let x = onRejected(error);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        })
      });
    });
  }
}
MyPromise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected);
}
MyPromise.prototype.finally = function (onFinally) {
  return this.then(
    res => MyPromise.resolve(onFinally()).then(() => res),
    err => MyPromise.resolve(onFinally()).then(() => { throw err; })
  );
}
const isPromise = (x) => {
  if (x !== null && (typeof x == 'object' || typeof x == 'function')) {
    try {
      const then = x.then;
      return typeof then == 'function';
    } catch (e) {
      return false
    }
  } else {
    return false
  }
}

MyPromise.all = function (values) {
  return new MyPromise((resolve, reject) => {
    let arr = [];
    let index = 0;
    const dealResult = (val, i) => {
      arr[i] = val;
      index++;
      if (index === values.length) {
        resolve(arr)
      }
    }
    for (let i = 0; i < values.length; i++) {
      let item = values[i];
      if (isPromise(item)) {
        item.then(res => {
          dealResult(res, i)
        }, reject)
      } else {
        dealResult(item, i)
      }
    }
  })
}

MyPromise.allSettled = function (values) {
  return new MyPromise((resolve) => {
    let arr = [];
    let index = 0;
    const dealResult = (val, i) => {
      arr[i] = val;
      index++;
      if (index === values.length) {
        resolve(arr)
      }
    }
    for (let i = 0; i < values.length; i++) {
      let item = values[i];
      if (isPromise(item)) {
        item.then(res => {
          dealResult({
            status: "fulfilled",
            value: res
          }, i)
        }, (err) => {
          dealResult({
            status: "rejected",
            reason: err
          }, i)
        })
      } else {
        dealResult({
          status: "fulfilled",
          value: item
        }, i)
      }
    }
  })
}

MyPromise.race = function (values) {
  return new Promise(function (resolve, reject) {
    for (let i = 0; i < values.length; i++) {
      let item = values[i];
      if (isPromise(item)) {
        item.then(res => {
          resolve(res)
        }, reject)
      } else {
        resolve(item)
      }
    }
  })
}

MyPromise.any = function (values) {
  return new Promise(function (resolve, reject) {
    const arr = [];
    for (let i = 0; i < values.length; i++) {
      let item = values[i];
      if (isPromise(item)) {
        item.then(res => {
          resolve(res)
        }, (err) => {
          arr.push(err);
          if (arr.length === values.length) {
            reject(new AggregateError("All promises were rejected"))
          }
        })
      } else {
        resolve(item)
      }
    }
  })
}


// 执行测试用例需要用到的代码
MyPromise.deferred = function () {
  let defer = {};
  defer.promise = new MyPromise((resolve, reject) => {
    defer.resolve = resolve;
    defer.reject = reject;
  });
  return defer;
}
try {
  module.exports = MyPromise
} catch (e) {
}

Promise/A+测试

yarn add promises-aplus-tests

然后输入命令行进行测试

promises-aplus-tests MyPromise.js

结果:

872 passing (18s)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值