JavaScript手写Promise、Promise.then()、Promise.all()、Promise.race()

我始终认为要想真正的理解一个API也好,内置对象也罢,最好的方式就是手写一遍。

😎 手写Promise

    const PENDING = "pending";
    const RESOLVED = "resolved";
    const REJECTED = "rejected";

    function MyPromise() {
      //保存初始化状态
      let selt = this;
      //初始化状态
      this.state = PENDING;
      //用于保存resolve或者rejected传入的值
      this.value = null;
      //用于保存resolve的回调函数
      this.resolvedCallbacks = [];
      //用于保存reject的回调函数
      this.rejectedCallbacks = [];

      //状态转变为resolved的方法
      function resolve(value) {
        //判断传入的元素是否为Promise值,如果是,则状态改变必须等待前一个状态改变后再进行改变
        if (value instanceof MyPromise) {
          return value.then(resolve, reject);
        }
        //保证代码的执行顺序为本轮事件循环的末尾
        setTimeout(() => {
          //只有状态为pending时才能转变
          if (self.state === PENDING) {
            //修改状态
            self.state = RESOLVED;
            //设置传入的值
            self.value = value;
            //执行回调函数
            self.resolvedCallbacks.forEach((callback) => {
              callback(value);
            });
          }
        }, 0);
      }

      //状态转变为rejected方法
      function reject(value) {
        //保证代码的执行顺序为本轮事件循环的末尾
        setTimeout(() => {
          //只有状态为pending时才能转变
          if (self.state === PENDING) {
            //修改状态
            self.state = REJECTED;
            //设置传入的值
            self.value = value;
            //执行回调函数
            self.rejectedCallbacks.forEach((callback) => {
              callback(value);
            });
          }
        }, 0);
      }

      //将两个方法传入函数执行
      try {
        fn(resolve, reject);
      } catch (e) {
        //遇到错误时,捕获错误,执行reject函数
        reject(e);
      }

      MyPromise.prototype.then = function (onResolved, onRejected) {
        //首先判断两个参数是否为函数类型,因为这两个参数是可选参数
        onResolved =
          typeof onResolved === "function"
            ? onResolved
            : function (value) {
                return value;
              };

        onRejected =
          typeof onRejected === "function"
            ? onRejected
            : function (error) {
                throw error;
              };

        //如果是等待状态,则将函数加入对应列表中
        if (this.state === PENDING) {
          this.resolvedCallbacks.push(onResolved);
          this.rejectedCallbacks.push(onRejected);
        }
        //如果状态已经凝固,则直接执行对应状态的函数
        if (this.state === RESOLVED) {
          onResolved(this.value);
        }

        if (this.state === REJECTED) {
          onRejected(this.value);
        }
      };
    }

🤓 手写Promise.then

then方法返回一个新的Promise实例,为了在Promise状态发生变化时再执行then里的函数,我们使用一个callbacks数组先把传给then的函数暂存起来,等状态改变时再调用

那么,怎么保证后一个then里的方法在前一个then(可能是异步)结束之后再执行呢?

我们可以将传给then函数和新Promiseresolve一起push到前一个Promisecallbacks数组中,达到承前启后的效果:

  • 承前:当前一个Promise完成后,调用其resolve变更状态,在这个resolve里会依次调用callbacks里的回调,这样就执行了then里的方法
  • 启后:上一步中,当then里的方法执行完成后,返回一个结果,如果这个结果是个简单的值,就直接调用新Promiseresolve,让其状态变更,这又会依次调用新Promisecallbacks数组里的方法,循环往复。如果返回的结果是个Promise,则需要等它完成之后再出发新Promiseresolve,所以可在其结果的then里调用新Promiseresolve
 	then(onFulfilled, onReject) {
      //保存前一个Promise的this
      const self = this;
      return new MyPromise((resolve, reject) => {
        //封装前一个Promise成功时执行的函数
        let fulfilled = () => {
          try {
            const result = onFulfilled(self.value); //承前
            return result instanceof MyPromise
              ? result.then(resolve, reject)
              : resolve(result); //启后
          } catch (e) {
            reject(e);
          }
        };
        //封装前一个Promise失败时执行的函数
        let rejected = () => {
          try {
            const result = onRejected(self.reason);
            return result instanceof MyPromise
              ? result.then(resolve, reject)
              : reject(result);
          } catch (e) {
            reject(e);
          }
        };
        switch (self.status) {
          case PENDING:
            self.onFulfilledCallbacks.push(fulfilled);
            self.onRejectedCallbacks.push(rejected);
            break;
          case FULFILLED:
            fulfilled();
            break;
          case REJECT:
            rejected();
            break;
        }
      });
    };

注意:

  • 连续多个then里的回调方法是同步注册的,但注册到了不同的callbacks数组中,因为每次then都返回新的Promise实例
  • 注册完成后开始执行构造函数中的异步事件,异步完成之后依次调用callbacks数组中提前注册的回调

🤔 手写Promise.all

  • 接收一个Promise实例的数组或具有Iterator接口的对象作为参数
  • 这个方法返回一个新的Promise对象
  • 遍历传入的参数,用Promise.resolve()将参数“包一层”,使其变成一个Promise对象
  • 参数所有回调成功才是成功,返回值数组与参数顺序一致
  • 参数数组其中一个失败,则触发失败状态,第一个触发失败状态的Promise错误信息作为Promise.all的错误信息
    function promiseAll(promises){
     return new Promise(function(resolve, reject){
       if(!Array.isArray(promises)){
         throw new TypeError(`argument must be a array`)
       }
       let resolvedCounter =0;//已resolve的promise数
       let promiseNum=promises.length;
       let resolvedResult =[];//暂存resolve结果的数组
       for(let i=0;i<promiseNum;i++){
         Promise.resolve(promises[i]).then(value=>{
           resolvedCounter++;
           resolvedResult[i]=value;
           if(resolvedCounter==promiseNum){
             return resolve(resolvedResult)
           }
         },error=>{
           return reject(error)
         })
       }
     })
   }
//test
   let p1=new Promise(function(resolve, reject){
       setTimeout(function(){
         resolve(1)
       },1000)
   });

   let p2=new Promise(function(resolve, reject){
       setTimeout(function(){
         resolve(2)
       },2000)
   });

   let p3=new Promise(function(resolve, reject){
       setTimeout(function(){
         resolve(3)
       },3000)
   });

   promiseAll([p3,p1,p2]).then(res=>{
     console.log(res);//[3,1,2]
   })

😋 手写Promise.race

该方法的参数是Promise实例数组,然后其then注册的回调方法是数组中的某一个Promise的状态变为fufilled的时候执行。因为Promise的状态只能改变一次,那么我们只需要把Promise.race中产生的Promise对象的resolve,注入到数组中的每一个Promise实例中的回调函数即可。

    Promise.race=function (args){
      return new Promise((resolve,reject)=>{
        for(let i=0,len=args.length;i<len;i++){
          args[i].then(resolve, reject)
        }
      })
    }

🫣 手写Promise.finally

finally (onFinally) {
    return new Promise((resolve, reject) => {
      this.then((result) => {
        onFinally();
        resolve(result);
      }, (reason) => {
        onFinally();
        reject(reason);
      });
    });
  }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值