满足PromiseA+规范的promise

149 阅读6分钟

基础版promise

1.先实现一个简易版的promise,符合下面几个规范稍后在完善

  1. promise必须是一个function 或者 object,必须有一个then方法。
  2. promise有三种状态 :请求态(pending), 完成态(fulfilled),拒绝态(rejected),初始状态是请求态pending,只能从pending -> fulfilled (对应一个成功的原因value)或者pending -> rejected (对应一个失败的原因 reason,且状态改变之后就不能更改。
  3. promise接受一个executor构造器 同步执行,构造器需要抛出异常,executor接受两个参数 resolve 和 reject, then方法接受两个参数onFulfilled 和 onRejected。
  4. onFulfilled 必须在调用resolve之后执行,onRejected 必须在调用reject之后执行, 如果excutor里面没有调用resolve或者reject的时候 promise仍然处于pending态,那么then方法的回调是不会执行的, 如果executor 里面异步调用(mutationobserver, setImmediate setTimeout调用 例子采用settimeout)了resolve或者reject 这个时候promise仍然处于pending态, 需要用发布订阅模式将then的函数回调保存下来,在下一个事件队列的宏任务中执行resolve或者reject的时候 发布之前保存下来的结果,然后依次执行。
  const PENDING = Symbol('pending');
  const FULFILLED = Symbol('fulfilled');
  const REJECTED = Symbol('rejected');
  class Promise {
    constructor(executor) {
      this.status = PENDING;
      this.value = undefined;
      this.reason = undefined;
      this.onFulfilledCallBackList = [];
      this.onRejectedCallBackList = [];
      const resolve = (value) => {
        if (this.status === PENDING) {
          this.status = FULFILLED;
          this.value = value;
          this.onFulfilledCallBackList.forEach((callBack) => callBack());
        }
      };
      const rejected = (reason) => {
        if (this.status === PENDING) {
          this.status = REJECTED;
          this.reason = reason;
          this.onRejectedCallBackList.forEach((callBack) => callBack());
        }
      };
      try {
        executor(resolve, rejected);
      } catch (error) {
        reject(error);
      }
    }
    then(onFulfilled, onRejected) {
      if (this.status === FULFILLED) {
        onFulfilled(this.value);
      }
      if (this.status === REJECTED) {
        onRejected(this.reason);
      }
      if (this.status === PENDING) {
        this.onFulfilledCallBackList.push(() => {
          onFulfilled(this.value);
        });
        this.onRejectedCallBackList.push(() => {
          onRejected(this.reason);
        });
      }
    }
  }

2.链式调用的promise

then(onFulfilled, onRejected) {
    let promise2 = new Promise((resolve, reject) => {
        if (this.status === FULFILLED) {
            try {
                let x = onFulfilled(this.value);
                resolve(x);
            } catch (error) {
                reject(error);
            }
        }
        if (this.status === REJECTED) {
            try {
                let x = onRejected(this.reason);
                resolve(x);
            } catch (error) {
                reject(error);
            }
        }
        if (this.status === PENDING) {
            this.onFulfilledCallBackList.push(() => {
                try {
                    let x = onFulfilled(this.value);
                    resolve(x);
                } catch (error) {
                    reject(error);
                }
            });
            this.onRejectedCallBackList.push(() => {
                try {
                    let x = onRejected(this.reason);
                    resolve(x);
                } catch (error) {
                    reject(error);
                }
            });
        }
    });
    return promise2;
}

3 完整版的promise

// 1) Promise 是一个类或者一个方法
// 2) Promise 有三种状态 pending (等待态) fulfilled (成功态) rejected (失败态)
//            默认为pending态
//            只有是pending态的时候才能更改状态为fulfilled 或者 rejected 状态一旦更改就不允许再次被修改
// 3) Promise 内部提供一个成功的value, 一个失败的reason
// 4) Promise 内部提供两个方法 一个resolve 一个reject
//            如果两个方法都不传 默认返回undefined
//            resolve或者reject不能抛异常 代码会直接报错
//            resolve接收成功的value reject接收失败的reason
//            调用resolve 会把状态从  pending 更改为  fulfilled
//            调用reject  会把状态从  pending 更改为  rejected
//            如果在executor 执行器中异步调用resolve或者reject 例如setTimeout调用
//            如果在异步任务重抛出异常 则会直接执行这个throw抛出的 不会走入到下面的then方法的回调了
//            then回调时候状态依然是pending态 需要发布订阅模式处理 将订阅的存放在数组里面
//            为什么存放的是一个数组呢 应为一个实例 可以then多次 一个多次订阅
//            成功的onFulfilledCallBacks 失败的onRejectedCallBacks
// 5) Promise 接收一个 executor 执行器, 默认会立即执行
//            第一个参数就是内部提供的resolve 第二个参数就是内部提供的参数reject
//            多个resolve跟reject嵌套的话 应该以最后一个的作为结果
// 6) Promise 有个then函数 默认有两个参数onFulfilled 和 onRejected
//            onFulfilled resolve或者reject调用之后返回的是一个普通值或者一个新的promise调用的resolve的值
//            将value作为参数传递给onFulfilled
//
//            onRejected  resolve和reject调用之后的回调返回一个promise的reject的值或者抛出异常 将reason作为参数传递给onRejected

//            then有返回值

// catch的特点是 如果都没有错误处理 一层层找 没有找到错误处理 会找最近的catch catch也是then

// promise中实现链式调用 返回一个新的promise

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
// 判断x的状态 是让promise2 变成 成功态 还是失败
// 此方法为了兼容所有的promise库 尽可能详细 不出错
function resolvePromise(promise2, x, resolve, reject) {
  /** PromiseA+ 2.3.2 不能引用同一个对象 会造成死循环*/
  if (promise2 === x) {
    return reject(
      new TypeError('Chaining cycle detected for promise #<Promise>')
    );
  }
  if ((typeof x === 'object' && x != null) || typeof x === 'function') {
    // x如果是对象或者函数 说明他有可能是个对象
    /** PromiseA+ 2.3.2.2
     * 取之可能会报错 then方法可能是由getter定义的
     *  Object.defineProperty(promise, 'then', {
     *   get () {
     *     throw new Error();
     *   }
     *  })
     * */
    let called;
    try {
      let then = x.then;
      if (typeof then === 'function') {
        /** PromiseA+ 2.3.2.2
         *  let obj = {
         *     index: 0,
         *     get then () {
         *        if (++this.index=== 2) throw error
         *     }
         *  }
         * obj.then 就会执行
         */
        // 相当于传进来的值是reject
        then.call(
          x,
          (y) => {
            // PromiseA+ 2.3.3.3
            // 防止一个promise调用多次 走完成功再走失败 或者走完失败 再走成功 或者一直走成功 或者一直走失败
            if (called) return;
            called = true;
            // 防止resolve 返回的还是promise 递归解析 直到是一个普通值为止
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            // PromiseA+ 2.3.3.3
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      // PromiseA+ 2.3.3.3
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    //这里有问题写的
    // 普通值 直接成功就好了
    resolve(x);
  }
}
function isPromise(x) {
  if ((typeof x === 'object' && x != null) || typeof x === 'function') {
    try {
      let x = x.then;
      if (typeof x.then === 'function') {
        return true;
      }
      return false;
    } catch (error) {
      return false;
    }
  }
  return false;
}
class Promise {
  constructor(executor) {
    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallBacks = [];
    this.onRejectedCallBacks = [];
    let resolve = (value) => {
      if (value instanceof Promise) {
        return value.then(resolve, reject);
      }
      if (this.status === PENDING) {
        //PromiseA+ 2.1.1
        this.status = FULFILLED;
        this.value = value;
        this.onFulfilledCallBacks.forEach((fn) => fn());
      }
    };
    let reject = (reason) => {
      if (this.status === PENDING) {
        //PromiseA+ 2.1.1
        this.status = REJECTED;
        this.reason = reason;
        this.onRejectedCallBacks.forEach((fn) => fn());
      }
    };
    try {
      //PromiseA+ 1.1.4
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  then(onFulfilled, onRejected) {
    //PromiseA+ 2.1.1
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v;
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (err) => {
            throw err;
          };
    // PromiseA+ 2.2.7
    // 为了实现链式调用 创建一个新的promise
    let promise2 = new Promise((resolve, reject) => {
      if (this.status === FULFILLED) {
        // 执行then中的方法 可能返回的是一个普通值 或者promise执行
        // 我要判断x的类型是不是一个promise 如果是promise的话 我要让这个promise执行
        // 并采用他的状态 作为promise的成功或者失败
        /** PromiseA+ 2.2.4*/
        setTimeout(() => {
          /** PromiseA+ 2.2.7.2*/
          try {
            // 一旦执行then方法报错 就走到外层then的错误处理中 调用promise2的reject方法中
            let x = onFulfilled(this.value);
            /** PromiseA+ 2.2.7.1*/
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      if (this.status === REJECTED) {
        /** PromiseA+ 2.2.4*/
        setTimeout(() => {
          /** PromiseA+ 2.2.7.2*/
          try {
            let x = onRejected(this.reason);
            /** PromiseA+ 2.2.7.1*/
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      if (this.status === PENDING) {
        this.onFulfilledCallBacks.push(() => {
          // 切片编程
          /** PromiseA+ 2.2.4*/
          setTimeout(() => {
            /** PromiseA+ 2.2.7.2*/
            try {
              // 一旦执行then方法报错 就走到外层then的错误处理中 调用promise2的reject方法中
              let x = onFulfilled(this.value);
              /** PromiseA+ 2.2.7.1*/
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.onRejectedCallBacks.push(() => {
          /** PromiseA+ 2.2.4*/
          setTimeout(() => {
            /** PromiseA+ 2.2.7.2*/
            try {
              // 一旦执行then方法报错 就走到外层then的错误处理中 调用promise2的reject方法中
              let x = onRejected(this.reason);
              /** PromiseA+ 2.2.7.1*/
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
          // 切片编程
        });
      }
    });
    return promise2;
  }
  catch(errCallBack) {
    return new Promise((resolve, reject) => {
      resolve(this.then(null, errCallBack));
    });
  }
  finally(callback) {
    return this.then(
      (value) => new Promise.resolve(callback()).then(() => value),
      (reason) =>
        new Promise.resolve(callback()).then(() => {
          throw reason;
        })
    );
  }
  static race(promises) { 
    return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            let result = promises[i];
            if(isPromise(result)){
                result.then(resolve,reject)
            }else{
                resolve(result);
            }
        }
    });
}
  static all(promises) {
    return new Promise((resolve, reject) => {
      let result = [];
      let times = 0;
      function processData(index, val) {
        result[index] = val;
        if (++times === promises.length) {
          resolve(result);
        }
      }
      for (let i = 0; i < promises.length; i++) {
        let p = promises[i];
        if (isPromise(p)) {
          p.then((data) => {
            processData(i, data); // 普通值
          }, reject);
        } else {
          processData(i, p); // 普通值
        }
      }
    });
  }
  static resolve(params) {
    return new Promise((resolve, reject) => {
      resolve(params);
    });
  };
  static reject(params) {
    return new Promise((resolve, reject) => {
      reject(params);
    });
  };
}

// npm install -g promises-aplus-tests
// promises-aplus-tests 文件名
Promise.defer = Promise.deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};
module.exports = Promise;

promiseA+规范