理解并实现你自己的Promise

本文主要探讨 1.promise 解决什么问题 .
                       2.promise解决的痛点,还能有哪些解决方法 。
                       3.promise 如何使用.
                      4.手动实现一个自己的promise 。
一.  Promise 出现以前,我们处理 异步网络请求,大概是这样,这还只是三个请求的样子,对于大型的项目,可能需要连续发多次请求, 这样的代码不利于阅读,更不利于维护。能不能用一种更加友好的代码组织方式,解决异步嵌套的问题,Promise出现。

getData( params,a=>{
     getData(a,b=>{                 
          getData(b,c=>{
           console.log(c);
        })
     })
})

Promise 是异步编程的一种解决方案,比传统的异步解决方案【回调函数】和【事件】更合理、更强大,已经被纳入ES6 的规范。使用promise 的 代码现在是这样的;相比回调来说,更规范易于维护,而且可以捕获异常信息,终止流程。

new Promise((resolve,reject)=>{
        setTimeout(()=>resolve('ok'))
          }).then()
          .then()
          .then()
          .catch(处理异常)

在promise 的基础上,结合Generator 、co 模块 ,现在已经衍生出了async /await 规范, 但是万变不离其宗,一起探究下promise如何实现的。上面的promise 包括 内部的回调函数(执行器),回调函数内部包括两个 参数 resolve 、reject  负责改变promise的状态,then中的函数在状态改变后执行。注意:更准确的说是 不是then函数在状态改变后执行, 而是 then中的回调函数在 promise 的 状态改变后执行。then 方法会把其中的 回调注册到对应的 resolveCallBack 和rejectCallBack队列中,等状态改变后依次执行对应队列中的回调。

要实现一个promise , 要包括那几部分?
1.执行器函数 handler ,调用promise后会立即执行,也是的入口。
2.状态 fulfiled、rejected、pending ,根据状态来执行then 中的回调。
3. 值 value , promise 的值 ,作为then 中回调函数的实参传入。
4. resolve ,reject ,执行器中传入的函数,改变promise的状态,值 。
5.then函数,挂载在构造函数的原型上,接收onFulfilled, onRejected 两个函数,分别在promise的状态变为fulfiled ,rejected时执行。

 const PENDING ='pending';
 const FULFILED ='fulfiled';
 const REJECTED = 'rejected'; //状态声明为常量

 class MyPromise{

   constructor(executor){

     this.status=PENDING;
      this.value = undefined;
      this.successCallback=[];
      this.errorCallback = [];
      function resolve (successValue){};
      function reject(errorValue){ }
   try {
       executor(resolve,reject); // 执行器函数
     }catch(e){
          reject(e)  
     }
    
   }



    then(){}
   
}

大体的框架如上, 下面实现下各个细节部分;
1).handler  执行器函数,作为promise 的入口,将传入的回调函数执行。达到改变promise状态的目的。

2).resolve ,reject函数, promise状态只能由pending  改变为fulfiled 或者 rejected ,且只能改变一次,所以先判断是否为pending,改变状态,接收promise的value 值,依次执行then 函数注册的回调。
改变状态、赋值value,最重要的一点:循环执行then方法注册到队列中的回调。
规范中,即使是一个已经变成resolve的promise,传递给then 函数的回调也要异步方式执行。保证回调函数执行前,所有的then 函数都注册到执行队列。这里我们用setTimeout 模拟异步。 
例如这种情形, const promise=new MyPromise(resolve=>resolve('success'))
promise.then(res=>console.log('a'));
promise.then(res=>console.log('b'));
注意: 在浏览器实际的执行中,then函数会随promise的调用立即执行 ,then 函数中的回调会在promise状态变成fulfiled或rejected时候,注册到微任务队列在下一轮事件循环时候执行。如下是resolve 的实现,reject类似。

 function resolve (successValue){
       if (that.status!==PENDING)return ;
         that.status=FULFILED;
         that.value=successValue;
setTimeout(()=>that.successCallback.forEach(fun=>fun(that.value)))};
3).then函数 ,promise 原型上挂载then方法用来访问当前或者最终的值;then 中传入可选函数 onFulfiled ,onRejected  。
onFulfiled ,onRejected都不是函数的时候, 默认赋值函数,返回then所属的promise 的值. 这样是为了then 未传函数的时候,可以把promise的值传递下去,例如情形:promise.resolve('success').then().then(res=>console.log(res));
onFulfiled,必须在promise 的状态为fulfiled时候才能调用,传入参数为promise的值,只能调用一次。
onRejected,必须在promise 的状态为rejected时候才能调用,传入参数为promise的值,只能调用一次。
如上述2)中then可能多次调用,then中需要维护两个队列 , 队列中的元素是then方法内注册的回调函数(onFulfilled, onRejected),每调用一次then,就向队列中注册一个回调,它们会在promise状态改变时被依次执行。
then 中返回新的promise  便于then的链式调用。then函数新返回的promise(promise2)的状态取决于onFulfilled,onRejected以及原promise1的状态。具体表现:
onFulfilled或onRejected 函数存在, 返回的值为 res ,promise2 的状态为fulfiled ,且value值 为res.
onFulfilled或onRejected 函数在运行时,抛出错误对象error,promise2 的状态为rejected ,值为抛出的错误对象error.
promise1 的状态为 fulfiled,且onFulfilled 函数不存在, promise2 的状态为fulfiled,值为promise1 的值;
promise1 的状态为 rejected,且onRejected 函数不存在, promise2 的状态为rejected,值为promise1 的值;
基于以上说明, 我们可以补充下模块的细节如下:
 

const  PENDING ='pending';
const FULFILED ='fulfiled';
const REJECTED ='rejected'; // 状态常量


class MyPromise{
  constructor(executor) {
      this.status=PENDING;
      this.value = undefined;
      this.successCallback=[];
      this.errorCallback = [];
     function resolve (successValue){
       if (this.status!==PENDING)return ;
         this.status=FULFILED;
         this.value=successValue;
      setTimeout(()=>this.successCallback.forEach(fun=>fun(successValue)),0); // 模拟then 中的回调函数在状态改变后异步执行。
        };

     function reject(errorValue){
          if (this.status!==PENDING)return ;
               this.status=REJECTED;
               this.value=errorValue;  
          setTimeout(()=>this.errorCallback.forEach(fun=>fun(errorValue)),0); // 同上
         }
     try {
        executor(resolve,reject); // 执行器函数
     }catch(e){
     reject(e) // catch 到错误对象reject
     }   

};

    then(onFulfiled,onRejected){
      return new MyPromise((resolveNext,rejectNext)=>{
       const  resolveNewPromise = value => {
        try{
            if( typeof onFulfiled !=='function'){
                  resolveNext(value) 
              }else {
            const res=onFulfiled(value);
            res instanceof MyPromise ? 
 res.then(resolveNext,rejectNext):resolveNext(res);  // then中的回调函数返回出来就是本身就是promise 实例,以实际返回的为主,接then函数处理,如果是是常值,将其作为promise的值resolve
        }
        }catch(e){
          rejectNext(e)
       }
    };
      const  rejectedNewPromise = value => {
          try{
      if( typeof onRejected!=='function'){
                rejectNext(value)
           }else {
            const res=onRejected(value);
          res instanceof MyPromise ? res.then(resolveNext,rejectNext):resolveNext(res);
          }
       }catch(e){rejectNext(e)}
    };
       if (this.status===PENDING){
         this.successCallback.push(resolveNewPromise);
         this.errorCallback.push(rejectedNewPromise);
        }
       if (this.status===FULFILED){
             setTimeout(()=> resolveNewPromise(this.value),0);// 当状态改变时候,将then中的回调函数注册成异步执行,在浏览器中注册成微任务在事件循环中下一轮执行。
           }
       if (this.status===REJECTED){
             setTimeout( ()=>rejectedNewPromise(this.value),0); // 同状态改变成FULFILED时候
       }
    });         
};


 static all(promiseList){
  
   return  new MyPromise((resolve,reject)=>{
         const  result =[];
    let   count= 0; 
      promiseList.forEach((p,index)=>{
   
       MyPromise.resolve(p).then(value=>{
               result[index]= value;
               count++;
          console.log('count',count);
             if(count===promiseList.length){
               console.log('value',value)
                   resolve(result)

                 }

          },reject);
})

})

}



static race() {
    return new MyPromise((resolve,reject)=>{
     for(const p of promiseList){
       Mypromise.resolve(p).then(resolve,reject)
    }
})

}

 static resolve(value){

    if(value instanceof MyPromise) return  value;
    return new MyPromise(resolve=>{
      resolve(value)
       });
}



  static reject(err){
  return new MyPromise((resolve,reject)=>{
         reject(err)
        })
}


}


var p1=new MyPromise((resolve,reject)=>{
        setTimeout(()=>{
         reject(3000);
        },1000);
      });

  var p2=new MyPromise((resolve,reject)=>{
      setTimeout(()=>{
      resolve(3000)
         },3000);
});
var p3=new MyPromise((resolve,reject)=>{
       setTimeout(()=>{
           reject(4000)
          },4000);
   
});
var promiseList = [p1,p2,p3];

MyPromise.race(promiseList).then(value=>{console.log(value)},err=>{console.log(err)});

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值