手写实现PromiseA+规范

1. 什么是promise

在以往我们处理多个JS请求的时候汪汪都是多个回调函数嵌套使用,使得代码难以阅读和维护,所以为了解决这个问题我们引入了新的异步解决方案就是Promise

抽象表达: Promise就是JS中的新的异步解决方案

具体表达: Promise就是一个构造函数,自身有all,race,resolve,reject等方法,原型上有then,catch方法

promise基础知识 promise基本使用

2. 手写实现PromiseA+规范

首先我们了解下promise基本使用

const p = new Promise((resolve, reject) => {
    resolve("success");
})
p.then(value => {
    console.log(value)
}, reason => {
    console.log(reason)
}
)

然后基于Promise/A+规范(英文),中文我们实现

实现代码,包括常用api

//定义状态变量
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class Promise {
  constructor(executor) {
    this.status = PENDING;
    //存放成功的值
    this.value = undefined;
    //存放失败的值
    this.reason = undefined;
    //存放回调函数
    this.callbacks = [];

    //调用此方法就是成功
    let resolve = (value) => {
       //如果第一个Promise传值就是一个Promise实例
      if (value instanceof Promise) {
        return value.then(resolve, reject);
      }
      //状态为pending时才能改变状态
      if (this.status !== PENDING) {
        return;
      }
       //修改状态
      this.status = FULFILLED;
      //保存成功的值  
      this.value = value;
      //resolve异步执行的时候在调用已经保存的回调函数,这里涉及到设计模式 发布订阅模式  依赖收集 -- 等待触发 -- 执行依赖
      if (this.callbacks.length > 0) {
        this.callbacks.forEach((callbackObj) => {
          callbackObj.onFulfilled(this.value);
        })
      }
    }

    let reject = (reason) => {
      //状态为pending时才能改变状态
      if (this.status !== PENDING) {
        return;
      }
      this.status = REJECTED;
      this.reason = reason;
      if (this.callbacks.length > 0) {
        this.callbacks.forEach((callbackObj) => {
          callbackObj.onRejected(this.reason);
        })
      }
    }

    //立即执行构造器函数,如果执行有异常就会直接调用reject
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }

  }

  //then 方法实现
  then(onFulfilled, onRejected) {
    //保证值的传递  
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
    //异常穿透的关键  
    onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason };
    //then调用返回一个promise  
    const promise2 = new Promise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            //执行onFulfilled  
            let result = onFulfilled(this.value);
            //处理promise对象返回,处理嵌套的promise对象,然后兼容其他类库的promise实现
            resolvePromise(result, promise2, resolve, reject);
          } catch (error) {
            reject(error)
          }
        })

      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let result = onRejected(this.reason);
            resolvePromise(result, promise2, resolve, reject);
          } catch (error) {
            reject(error)
          }
        })
      }
      //满足异步执行resolve/reject情况
      if (this.status === PENDING) {
        this.callbacks.push({
          onFulfilled: () => {
            setTimeout(() => {
              try {
                let result = onFulfilled(this.value);
                resolvePromise(result, promise2, resolve, reject);
              } catch (error) {
                reject(error)
              }
            })
          },
          onRejected: () => {
            setTimeout(() => {
              try {
                let result = onRejected(this.reason);
                resolvePromise(result, promise2, resolve, reject);
              } catch (error) {
                reject(error)
              }
            })
          }
        })
      }
    })

    return promise2;
  }

  catch(onRejected){
    return this.then(undefined, onRejected);
  }

  //Promise.resolve方法
  static resolve = function (value) {
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(resolve, reject);
      } else {
        resolve(value);
      }
    })
  }

  //Promise.reject方法
  static reject = function (reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    })
  }

  //Promise.all方法
  static all = function (promiseArr) {
    let length = promiseArr.length;
    let resolveArr = new Array(length);
    let resolveCount = 0; //返回成功的个数
    return new Promise((resolve, reject) => {
      promiseArr.forEach((promiseItem, index) => {
        Promise.resolve(promiseItem).then(
          value => {
            resolveCount++;
            resolveArr[index] = value;
            if (length === resolveCount) {
              resolve(resolveArr);
            }
          },
          reject
        )
      })
    })
  }

  //Promise.race方法
  static race = function(promiseArr){
    return new Promise((resolve, reject) => {
      promiseArr.forEach((promiseItem) => {
        Promise.resolve(promiseItem).then(resolve, reject);
      })
    })
  }
}

//实现链式调用,值穿透
function resolvePromise(result, promise2, resolve, reject) {
   //对返回的 result 进行判断得出返回的promise状态
              /*
                1.如果抛出异常就返回失败的promise,value为异常
                2. 如果为非promise的基本类型,返回成功的promise ,value就为该基本类型
                3. 如果为promise对象,返回的promise结果就为该promise的结果
                4. 如果为thenable类型,即有then函数或者属性的函数或者对象,所以为函数就执行该对象或者函数的then,不为就以该类型作为参数执行promise
              */
  //避免循环调用等待
  if (result === promise2) {
    return reject(new TypeError('chaining cycle detected for promise!'))
  }
  //严格判断类型
  if (result && (typeof result === 'object' || typeof result === 'function')) {
    let called;//判断调用过resolve/reject没,防止重复调用
    try {
      //tyrcatch保证调用其他库的promise或者thenable 设置了then不能被调用而导致报错(Object.defineProperty)
      let then = result.then;
      if (typeof then === 'function') {
        //这样保证有些库设置了then可取的个数,比如设置了Object.defineProperty 比如 第一次then=result.then后再 then=result.then就报错
        then.call(result, value => {
          if (called) return;
          called = true;
          resolvePromise(value, promise2, resolve, reject);
          //resolve(value)
        }, reason => {
          if (called) return;
          called = true;
          reject(reason);
        });
      } else {
        resolve(result);
      }
    } catch (error) {
      if (called) return;
      called = true;
      reject(error);
    }
  } else {
    resolve(result);
  }
}

module.exports = Promise;

3. 测试是否满足PromiseA+规范

下载测试工具

npm i promises-aplus-tests -g 

将如下代码加到实现的Promise.js 文件中

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

运行命令

promises-aplus-tests [Promise.js文件名]
Last modification:June 5, 2021
如果觉得我的文章对你有用,请随意赞赏