手写代码实现符合A+规范的Promise,完美通过测试

前言

在学习过程中建议配合参考MDN promisePromise/A+规范(中文翻译)Promise/A+规范(中文翻译),可以使用MDN中案例或者promises-aplus-tests来测试。
我会在最底下放promises-aplus-tests的测试方法和完整代码。

实现Promise

构造函数

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class Promise {
  constructor(executor) {
    //状态
    this.status = PENDING;
    //成功值
    this.value = undefined;
    //失败值
    this.reason = undefined;
    //then回调数组
    this.onResolveCallBacks = []
    this.onRejectCallBacks = []

    const resolve = (value) => {
      if (this.status === PENDING) {
        this.status = FULFILLED
        this.value = value
  
        //执行then resolve回调方法
        this.onResolveCallBacks.forEach(fn => fn())
      }
    };
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED
        this.reason = reason
  
        //执行then reject回调方法
        this.onRejectCallBacks.forEach(fn => fn())
      }
    };

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

Promise.prototype.then方法

then() 方法返回一个 Promise 。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。返回Promise可以进行链式调用。
then方法是最重要也是最难的地方,弄懂了其他都简单了。

then(onFulfilled, onRejected) {
  //如果没有回调函数则将上个resolve/reject结果返回给下一个
  onFulfilled =
    typeof onFulfilled === "function" ? onFulfilled : (value) => value;
  onRejected =
    typeof onRejected === "function"
      ? onRejected
      : (reason) => {
          throw reason;
        };
  //返回promise对象
  let promise2 = new Promise((resolve, reject) => {
    const resolveMicrotask = () => {
      queueMicrotask(() => {
        try {
          let x = onFulfilled(this.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (error) {
          reject(error);
        }
      });
    };
    const rejectMicrotask = () => {
      queueMicrotask(() => {
        try {
          let x = onRejected(this.reason);
          resolvePromise(promise2, x, resolve, reject);
        } catch (error) { 
          reject(error);
        }
      });
    };
    if (this.status === FULFILLED) {
      //异步(微任务)调用回调函数
      resolveMicrotask();
      return;
    }
    if (this.status === REJECTED) {
      rejectMicrotask();
      return;
    }
    if (this.status === PENDING) {
      this.onResolveCallBacks.push(resolveMicrotask);
      this.onRejectCallBacks.push(rejectMicrotask);
      return;
    }
  });

  return promise2;
}
/**
 * Promise解决程序
 */
const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x) {
    reject(new TypeError("Chaining cycle detected for promise #<Promise>"));
  }
  //x是函数或者对象
  else if ((typeof x === "object" && x != null) || typeof x === "function") {
    //x.then取出或者调用抛出异常返回错误
    let called = false; // 标记 resolve或reject只执行一次,优先采用首次调用
    try {
      let then = x.then;
      //如果这个值是thenable(即带有"then" 方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态
      if (typeof then === "function") {
        then.call(x,
          (y) => {
            if (called) return;
            called = true;
            //thenable 的y可能会返回promise 所有再进一步处理
            return resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      }
      //then不是函数返回x
      else {
        resolve(x);
      }
    } catch (error) {
      //若promise已解决或拒绝则忽略异常
      if (called) return;
      reject(error);
    }
  }
  //x不是函数或者对象
  else {
    resolve(x);
  }
};

Promise.prototype.catch()方法

catch() 方法返回一个Promise ,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。

//等于只有onRejected的then
catch (onRejected) {
   return this.then(null, onRejected)
 }

Promise.prototype.finally()方法

  • finally() 方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise是否成功完成后都需要执行的代码提供了一种方式。
  • finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。
  • finally的回调函数如果返回一个resultPromise,那么Promise的结果根据resultPromise的执行结果来决定,否则回上一个Promise的执行结果
finally(callback) {
  //如果回调函数返回promise,则返回此promise的resolve/reject结果
  //如果回调函数不返回promise,则返回上一个promise的resolve/reject结果
  return this.then(value => {
    return Promise.resolve(callback()).then(()=>value)
  }, reason => {
    return Promise.reject(callback()).then(()=>reason)
  })
}

resolve()方法

Promise.resolve(value)方法返回一个以给定值解析后的Promise 对象。

  • 如果这个值是一个 promise ,那么将返回这个 promise
  • 如果这个值是thenable(即带有"then" 方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态
  • 否则返回的promise将以此值完成。
resolve(value) {
  //如果这个值是一个 promise ,那么将返回这个 promise
  if (value instanceof Promise) {
    return value
    //如果这个值是thenable(即带有"then" 方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;
  } else if (value && value.then && typeof value.then === 'function') {
    let p = new Promise((resolve, reject) => {
      resolve()
    })
    p.then = value.then
    return p
  } else {
    return new Promise((resolve, reject) => {
      resolve(value)
    })
  }
}

reject()方法

Promise.reject()方法返回一个带有拒绝原因的Promise对象。

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

all()方法

Promise.all() 方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。

  • 如果传入的参数是一个空的可迭代对象,则会同步地返回一个已完成(already resolved)状态的 Promise。
  • 如果传入的参数不包含任何 promise,则返回一个异步完成(asynchronously resolved) Promise。
  • 其它情况下返回一个处理中(pending)的Promise。这个返回的 promise 之后会在所有的 promise 都完成或有一个 promise 失败时异步地变为完成或失败。返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。
all(array) {
  //判断iterator类型
  if (typeof array[Symbol.iterator] !== 'function') {
    throw (new TypeError(`${array} is not iterable`))
  }
  let resultArr = []
  let flag = 0
  
  return new Promise((resolve, reject) => {
  	//空迭代时同步返回完成状态的Promise
    if (array.length === 0) {
      resolve(array)
      return
    }
    const processResultByKey = (value, index) => {
      resultArr[index] = value
      flag++
      //所有处理完返回成功结果
      if (flag === array.length) {
        resolve(resultArr)
      }
    }
    //遍历执行
    for (let i = 0; i < array.length; i++) {
      let item = array[i]
      if (item instanceof Promise) {
        item.then(r => {
          processResultByKey(r, i)
        }, e => {
          //如果有任何一个promise返回reject,则 all直接返回reject
          reject(e)
        })
      } else {
        //如果不是promise 则异步返回
        queueMicrotask(() => {
          processResultByKey(item, i)
        });
      }
    }
  })
}

allSettled()方法

Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。

allSettled(array) {
  //判断iterator类型
  if (typeof array[Symbol.iterator] !== 'function') {
    throw (new TypeError(`${array} is not iterable`))
  }
  let resultArr = []
  let flag = 0
  return new Promise((resolve, reject) => {
    if (array.length === 0) {
      resolve(array)
      return
    }
    const processResultByKey = (item, index, type) => {
      //结果返回对象数组
      if (type === 1) {
        resultArr[index] = {
          status: item.status,
          value: item.value
        }
      } else {
        resultArr[index] = {
          status: item.status,
          reason: item.reason
        }
      }
      flag++
      if (flag === array.length) {
        resolve(resultArr)
      }
    }
    for (let i = 0; i < array.length; i++) {
      let item = array[i]
      if (item instanceof Promise) {
        item.then(() => {
          processResultByKey(item, i, 1)
        }, () => {
          processResultByKey(item, i, 2)
        })
      } else {
        let p = Promise.resolve(item)
        p.then(() => {
          processResultByKey(p, i, 1)
        })
      }
    }
  })
}

测试代码

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).then((results) => {
  console.log(results);
});

在这里插入图片描述

any()方法

Promise.any() 接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。

  • 如果传入的参数是一个空的可迭代对象, 这个方法将会同步返回一个已经完成的 promise。
  • 如果传入的任何一个 promise 已成功, 或者传入的参数不包括任何 promise, 那么 Promise.any 返回一个异步成功的 promise。
  • 如果所有传入的 promises 都失败, Promise.any 将返回异步失败,和一个 AggregateError 对象,它继承自 Error,有一个 error 属性,属性值是由所有失败值填充的数组。
any(array) {
  //判断iterator类型
  if (typeof array[Symbol.iterator] !== 'function') {
    throw (new TypeError(`${array} is not iterable`))
  }
  let resultArr = []
  let flag = 0
  return new Promise((resolve, reject) => {
    if (array.length === 0) {
      reject(array)
      return
    }
    const processResultByKey = (value, index) => {
      resultArr[index] = value
      flag++
      if (flag === array.length) {
        reject(new AggregateError(resultArr,'All promises were rejected'))
      }
    }
    for (let i = 0; i < array.length; i++) {
      let item = array[i]
      if (item instanceof Promise) {
        item.then(r => {
          //如果有任何一个promise返回resolve,则all直接返回resolve
          resolve(r)
        }, e => {
          processResultByKey(e, i)
        })
      } else {
        //如果不是promise 则异步返回
        queueMicrotask(() => {
          processResultByKey(item, i)
        });
      }
    }
  })
}

race()方法

Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

  • 它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。
  • 如果传的迭代是空的,则返回的 promise 将永远等待。
  • 如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 race 将解析为迭代中找到的第一个值。
race(array) {
  //判断iterator类型
  if (typeof array[Symbol.iterator] !== 'function') {
    throw (new TypeError(`${array} is not iterable`))
  }
  return new Promise((resolve, reject) => {
    if (array.length === 0) {
      return
    }
    for (let i = 0; i < array.length; i++) {
      let item = array[i]
      if (item instanceof Promise) {
        item.then(r => {
          resolve(r)
        }, e => {
          //如果有任何一个promise返回reject,则all直接返回reject
          reject(e)
        })
      } else {
        //如果不是promise 则异步返回
        queueMicrotask(() => {
          resolve(r)
        });
      }
    }
  })
}
}

测试

使用promises-aplus-tests库进行测试
1.安装

yarn add promises-aplus-tests

2.在package.json中加入脚本

"scripts": {
    "testPromise": "promises-aplus-tests /promise.js"
  },

3.在promise.js中插入以下代码

Promise.defer = Promise.deferred = function() {
  let deferred = {};

  deferred.promise = new Promise((resolve, reject) => {
    deferred.resolve = resolve;
    deferred.reject = reject;
  });
  return deferred;
};

module.exports = Promise;

4.结果
通过全部测试
在这里插入图片描述

完整代码

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

class Promise {
  constructor(executor) {
    //状态
    this.status = PENDING;
    //成功值
    this.value = undefined;
    //失败值
    this.reason = undefined;
    //then回调数组
    this.onResolveCallBacks = [];
    this.onRejectCallBacks = [];

    const resolve = (value) => {
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;

        //执行then resolve回调方法
        this.onResolveCallBacks.forEach((fn) => fn());
      }
    };
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;

        //执行then reject回调方法
        this.onRejectCallBacks.forEach((fn) => fn());
      }
    };

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

  then(onFulfilled, onRejected) {
    //如果没有回调函数则将上个resolve/reject结果返回给下一个
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason;
          };
    //返回promise对象
    let promise2 = new Promise((resolve, reject) => {
      const resolveMicrotask = () => {
        queueMicrotask(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      };
      const rejectMicrotask = () => {
        queueMicrotask(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) { 
            reject(error);
          }
        });
      };
      if (this.status === FULFILLED) {
        //异步(微任务)调用回调函数
        resolveMicrotask();
        return;
      }
      if (this.status === REJECTED) {
        rejectMicrotask();
        return;
      }
      if (this.status === PENDING) {
        this.onResolveCallBacks.push(resolveMicrotask);
        this.onRejectCallBacks.push(rejectMicrotask);
        return;
      }
    });

    return promise2;
  }
  //等于只有onRejected的then
  catch(onRejected) {
    return this.then(null, onRejected);
  }

  finally(callback) {
    //如果回调函数返回promise,则返回此promise的resolve/reject结果
    //如果回调函数不返回promise,则返回上一个promise的resolve/reject结果
    return this.then(
      (value) => {
        return Promise.resolve(callback()).then(() => value);
      },
      (reason) => {
        return Promise.reject(callback()).then(() => reason);
      }
    );
  }

  static resolve(value) {
    //如果这个值是一个 promise ,那么将返回这个 promise
    if (value instanceof Promise) {
      return value;
      //如果这个值是thenable(即带有"then" 方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;
    } else if (value && value.then && typeof value.then === "function") {
      let p = new Promise((resolve) => {
        resolve();
      });
      p.then = value.then;
      return p;
    } else {
      return new Promise((resolve) => {
        resolve(value);
      });
    }
  }

  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  }

  static all(array) {
    //判断iterator类型
    if (typeof array[Symbol.iterator] !== "function") {
      throw new TypeError(`${array} is not iterable`);
    }
    let resultArr = [];
    let flag = 0;
    return new Promise((resolve, reject) => {
      if (array.length === 0) {
        resolve(array);
        return;
      }
      const processResultByKey = (value, index) => {
        resultArr[index] = value;
        flag++;
        if (flag === array.length) {
          resolve(resultArr);
        }
      };
      for (let i = 0; i < array.length; i++) {
        let item = array[i];
        if (item instanceof Promise) {
          item.then(
            (r) => {
              processResultByKey(r, i);
            },
            (e) => {
              //如果有任何一个promise返回reject,则all直接返回reject
              reject(e);
            }
          );
        } else {
          //如果不是promise 则异步返回
          queueMicrotask(() => {
            processResultByKey(item, i);
          });
        }
      }
    });
  }

  static allSettled(array) {
    //判断iterator类型
    if (typeof array[Symbol.iterator] !== "function") {
      throw new TypeError(`${array} is not iterable`);
    }
    let resultArr = [];
    let flag = 0;
    return new Promise((resolve) => {
      if (array.length === 0) {
        resolve(array);
        return;
      }
      const processResultByKey = (item, index, type) => {
        //结果返回对象数组
        if (type === 1) {
          resultArr[index] = {
            status: item.status,
            value: item.value,
          };
        } else {
          resultArr[index] = {
            status: item.status,
            reason: item.reason,
          };
        }
        flag++;
        if (flag === array.length) {
          resolve(resultArr);
        }
      };
      for (let i = 0; i < array.length; i++) {
        let item = array[i];
        if (item instanceof Promise) {
          item.then(
            () => {
              processResultByKey(item, i, 1);
            },
            () => {
              processResultByKey(item, i, 2);
            }
          );
        } else {
          let p = Promise.resolve(item);
          p.then(() => {
            processResultByKey(p, i, 1);
          });
        }
      }
    });
  }

  static any(array) {
    //判断iterator类型
    if (typeof array[Symbol.iterator] !== "function") {
      throw new TypeError(`${array} is not iterable`);
    }
    let resultArr = [];
    let flag = 0;
    return new Promise((resolve, reject) => {
      if (array.length === 0) {
        reject(array);
        return;
      }
      const processResultByKey = (value, index) => {
        resultArr[index] = value;
        flag++;
        if (flag === array.length) {
          reject(resultArr, "All promises were rejected");
        }
      };
      for (let i = 0; i < array.length; i++) {
        let item = array[i];
        if (item instanceof Promise) {
          item.then(
            (r) => {
              //如果有任何一个promise返回resolve,则all直接返回resolve
              resolve(r);
            },
            (e) => {
              processResultByKey(e, i);
            }
          );
        } else {
          //如果不是promise 则异步返回
          queueMicrotask(() => {
            processResultByKey(item, i);
          });
        }
      }
    });
  }

  //一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
  static race(array) {
    //判断iterator类型
    if (typeof array[Symbol.iterator] !== "function") {
      throw new TypeError(`${array} is not iterable`);
    }
    return new Promise((resolve, reject) => {
      if (array.length === 0) {
        return;
      }
      for (let i = 0; i < array.length; i++) {
        let item = array[i];
        if (item instanceof Promise) {
          item.then(
            (r) => {
              resolve(r);
            },
            (e) => {
              //如果有任何一个promise返回reject,则all直接返回reject
              reject(e);
            }
          );
        } else {
          //如果不是promise 则异步返回
          queueMicrotask(() => {
            resolve(item);
          });
        }
      }
    });
  }
}

const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x) {
    reject(new TypeError("Chaining cycle detected for promise #<Promise>"));
  }
  //x是函数或者对象
  else if ((typeof x === "object" && x != null) || typeof x === "function") {
    //x.then取出或者调用抛出异常返回错误
    let called = false; // 标记 resolve或reject只执行一次,优先采用首次调用
    try {
      let then = x.then;
      //如果这个值是thenable(即带有"then" 方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态
      if (typeof then === "function") {
        then.call(x,
          (y) => {
            if (called) return;
            called = true;
            //thenable 的y可能会返回promise 所有再进一步处理
            return resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      }
      //then不是函数返回x
      else {
        resolve(x);
      }
    } catch (error) {
      if (called) return;
      called = true;
      reject(error);
    }
  }
  //x不是函数或者对象
  else {
    resolve(x);
  }
};

Promise.defer = Promise.deferred = function() {
  let deferred = {};

  deferred.promise = new Promise((resolve, reject) => {
    deferred.resolve = resolve;
    deferred.reject = reject;
  });
  return deferred;
};

module.exports = Promise;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值