Promises/A+ 规范写一个自己的Promise

1,309 阅读5分钟

前言

百度了很多次别人写的promise ,也是一时兴起 今天自己写了一个并且做了这么一个记录

Promises/A+

同学们:此处自行查阅Promises/A+规范

Just do it

接下来我根据我自己习惯看规范

  1. “promise” is an object or function with a then method whose behavior conforms to this specification. class Promise{}和function Promise{} 都行,那我写的是class
 class Promise{
        constructor(execuctor) {}
    }
 export default Promise
  1. A promise must be in one of three states: pending, fulfilled, or rejected.... 每个promise 都有三个状态 ,且pedding状态时可变更(通过resolve和reject) fulfilled, or rejected,但只支持变更一次,不能转变成任何其他状态。

  2. “reason” is a value that indicates why a promise was rejected. “value” is any legal JavaScript value (including undefined, a thenable, or a promise). resolve() 和reject() 的参数 和其值的初始化,结合2做状态变更处理

//状态常量
/**初始化状态*/
const PENDING = "PENDING";
/**成功状态*/
const FULFILLED = "FULFILLED";
/**失败状态*/
const REJECTED = "REJECTED";

 class Promise{
        constructor(execuctor) {
          this.status = PENDING;
          this.value = undefined;
          this.reason = undefined;
          const resolve = (val) => {
              // 状态变更后 不可以在更改为其他状态,只支持修改一次
              if (this.status === PENDING) {
                this.value = val; //成功状态时 value的赋值
                this.status = FULFILLED; //修改状态
              }
            };
          const reject = (err) => {
              // 状态变更后 不可以在更改为其他状态,只支持修改一次
              if (this.status === PENDING) {
                this.reason = err; //失败状态时的 reason的赋值
                this.status = REJECTED; //修改状态
              }
        }

    }

  1. “exception” is a value that is thrown using the throw statement. throw 语句抛出的异常。这里按照我自己的理解 用try,catch 捕获异常的时候 调用reject(err)
try {
      execuctor(resolve, reject);
    } catch (err) {
      reject(err);
    }

  1. A promise’s then method accepts two arguments: promise.then(onFulfilled, onRejected).... then 方法的支持,FULFILLED执行onFulfilled,REJECTED执行onRejected而且参数均得是函数,这里规范我们没有全部粘贴
then(onFulfilled, onRejected) {
    if (this.status === FULFILLED) {
      onFulfilled(this.value);
    }
    if (this.status === REJECTED) {
      onRejected(this.reason);
    }

  1. promise的解决问题是异步回调地狱的问题,当前的实现还是同步执行,如果遇到setTimeout包裹resolve 延迟执行,那then拿到的status会一直是pending,无法执行对应函数
  • 🌰
let promise = new Promise((resolve, reject) => {
  console.log("promise begin");
  setTimeout(() => {
    resolve("成功");
  }, 1000);
});
promise.then(
//无法打印,因为计时器执行完后then早就执行完了所以then里拿到的状态始终是pending
  (res) => {
    console.log(res);
  },
  (err) => {
    console.log(err);
  }
);

  • 解决:执行到then里的时候将回调函数缓存在数组里,结合发布订阅模式 统一做发布
constructor(){
//构造器里新增两个数组做缓存
    this.onFulfilledCallback=[]
    this.onRejectedCallback=[]
}
//修改then的实现,执行then的时候 做onFulfilled,onRejected,push进缓存数组的操作
then(onFulfilled, onRejected) {
    if (this.status === PENDING) {
      this.onFulfilledCallback.push(() => {
        onFulfilled(this.value);
      });
      this.onRejectedCallback.push(() => {
        onRejected(this.reason);
      });
    }
  }
//resolve方法里 新增 遍历onFulfilledCallback 数组并执行 
this.onFulfilledCallback.forEach(fn=>fn())
//reject方法里 同理
this.onRejectedCallback.forEach(fn=>fn())

  • 重新执行上面setTimeout的例子 这时候就可以 正常打印了
  1. then may be called multiple times on the same promise..... then must return a promise promise2 = promise1.then(onFulfilled, onRejected);....
  • then方法返回一个promise对象用于链式调用
  • then里接受到的状态是上一个then的执行成功与否状态
  • 如果是成功就调用成功回调函数,如果是失败就调用失败回调函数..
  • 上一个then执行结果x作为当前return的整个promise的resolve()和reject()的入参
  then(onFulfilled, onRejected) {
      //返回一个promise对象实现链式调用,包裹原来的then内部代码先
     let promise2 = new Promise((resolve, reject) => {
         if (this.status === FULFILLED) {
           try { 
               let x = onFulfilled(this.value);
               resolve(x); 
             } catch (err) {
             reject(err); 
             }
            }
         if (this.status === REJECTED) {
           try { 
           // 上一个then执行结果x作为当前then的resolve的入参数 
               let x = onRejected(this.reason); 
               resolve(x);
             } catch (err) { 
               reject(err); 
             } 
           }

        if (this.status === PENDING) {
        //异步调用
        this.onFulfilledCallback.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolve(x);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });
        this.onRejectedCallback.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolve(x);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });
      }
     }
 }

测试

  • 写到这里 基本功能 reject ,resolve ,和then的链式调用 基本 实现

  • 代码测试插件用的是 code run (按照指南[VS code插件分享之 --- Run Code]

image.png

  • 测试结果 image.png

完整代码

//状态常量
/**初始化状态*/
const PENDING = "PENDING";
/**成功状态*/
const FULFILLED = "FULFILLED";
/**失败状态*/
const REJECTED = "REJECTED";
class Promise {
  constructor(execuctor) {
    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;
    const resolve = (val) => {
      // 状态变更后 不可以在更改为其他状态,只支持修改一次
      if (this.status === PENDING) {
        this.value = val; //成功状态时 value的赋值
        this.status = FULFILLED; //修改状态
      }
    };
    const reject = (err) => {
      // 状态变更后 不可以在更改为其他状态,只支持修改一次
      if (this.status === PENDING) {
        this.reason = err; //失败状态时的 reason的赋值
        this.status = REJECTED; //修改状态
      }
    };
    try {
      execuctor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
    then(onFulfilled, onRejected) {
      //1.返回一个promise对象实现链式调用
    let promise2 = new Promise((resolve, reject) => {
      //2.支持then调用后 then里接受到的状态是上一个then的执行成功与否状态
      //  所以 this.status 在这时候就不仅有PENDING了
      if (this.status === FULFILLED) {
        //  3.函数执行时的throw Error的处理,同理将所有的都加上错误捕获
        try {
          let x = onFulfilled(this.value);
          // 上一个then执行结果x作为当前then的resolve的入参数
          // 这里要注意 只要上一个then有return 值 就调用当前then的resolve 捕获了异常才调用reject
          resolve(x);
        } catch (err) {
          reject(err);
        }
      }
      if (this.status === REJECTED) {
        try {
          // 上一个then执行结果x作为当前then的reject的入参数
          let x = onRejected(this.reason);
          // 这里要注意 只要上一个then有return 值 就调用当前then的resolve 捕获了异常才调用reject
          resolve(x);
        } catch (err) {
          reject(err);
        }
      }
      //  4. 为了支持链式调用 第一次的then也要将执行结果x 传给对应的resolve或者reject
      if (this.status === PENDING) {
        //异步调用
        this.onFulfilledCallback.push(() => {
          try {
            let x = onFulfilled(this.value);
            resolve(x);
          } catch (err) {
            reject(err);
          }
        });
        this.onRejectedCallback.push(() => {
          try {
            let x = onRejected(this.reason);
            resolve(x);
          } catch (err) {
            reject(err);
          }
        });
      }
    });
    return promise2;
  }
}
 export default Promise



小结

到这里就写完了一个简易支持then链式调用promise的全部代码 promise2.0