美文网首页
浅谈Promise之参照Promise/A+规范实现Promis

浅谈Promise之参照Promise/A+规范实现Promis

作者: October_yang | 来源:发表于2018-01-15 16:10 被阅读0次

    在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够直观,就是常说的回调地狱,通常通过promise来解决

    Promise本意是承诺,在程序中的意思就是承诺我过一段时间后会给你一个结果。 什么时候会用到过一段时间?答案是异步操作,异步是指可能比较长时间才有结果的才做,例如网络请求、读取本地文件等

    按照Promise/A+规范来实现一个Promise类

    构造函数初始化逻辑

    const PENDING =  'pending';//初始态
    const FULFILLED =  'fulfilled';//初始态
    const REJECTED =  'rejected';//初始态
    let self = this;//先缓存当前promise实例
    self.status = PENDING;//设置状态
    self.onResolvedCallbacks = [];//定义存放成功的回调的数组
    self.onRejectedCallbacks = []; //定义存放失败回调的数组
    

    executor执行器,包含两个参数,分别是resolve 解决和reject 拒绝,new Promise这个executor就会执行

    Promise有三个状态:初始化状态为pending,成功状态为fulfilled,失败状态rejected,如果代码一旦成功就不会走向失败,若 一直pending 永远不给你明确的答复

    当调用以下方法的时候,如果promise状态为pending的话可以转成成功态,如果已经是成功态或者失败态了,则什么都不做

      function resolve(value){ 
        if(value!=null &&value.then&&typeof value.then == 'function'){
          return value.then(resolve,reject);
        }
        setTimeout(function(){
          if(self.status == PENDING){
            self.status = FULFILLED;
            self.value = value;
            self.onResolvedCallbacks.forEach(cb=>cb(self.value));
          }
        })
      }
      function reject(reason){ //2.1.2
        setTimeout(function(){
          if(self.status == PENDING){
            self.status = REJECTED;
            self.value = reason;
            self.onRejectedCallbacks.forEach(cb=>cb(self.value));
          }
        });
      }
    }
    

    因为此函数执行可能会异常,所以需要捕获,如果出错了,需要用错误对象reject,如果这函数执行失败了,则用失败的原因reject这个promise,需要用try...catch(e)...进行处理

      try{
        executor(resolve,reject);
      }catch(e){
        reject(e);
      };
    

    Promise的解析过程

    function resolvePromise(promise2,x,resolve,reject){
      if(promise2 === x){
        return reject(new TypeError('循环引用'));
      }
      let called = false;
      if(x instanceof Promise){
        if(x.status == PENDING){
          x.then(function(y){
            resolvePromise(promise2,y,resolve,reject);
          },reject);
        }else{
          x.then(resolve,reject);
        }
      }else if(x!= null &&((typeof x=='object')||(typeof x == 'function'))){
       try{
         let then = x.then;
         if(typeof then == 'function'){
           then.call(x,function(y){
              if(called)return;
              called = true;
              resolvePromise(promise2,y,resolve,reject)
           },function(err){
             if(called)return;
             called = true;
             reject(err);
           });
         }else{
           resolve(x);
         }
       }catch(e){
         if(called)return;
         called = true;
         reject(e);
       }
      }else{
        resolve(x);
      }
    }
    

    then方法就是用来指定Promise 对象的状态改变时确定执行的操作,resolve 时执行第一个函数(onFulfilled),reject 时执行第二个函数(onRejected)
    此方法中,如果成功和失败的回调没有传,则表示这个then没有任何逻辑,只会把值往后抛

    Promise.prototype.then = function(onFulfilled,onRejected){
      onFulfilled = typeof onFulfilled == 'function'?onFulfilled:function(value){return  value};
      onRejected = typeof onRejected == 'function'?onRejected:reason=>{throw reason};
      let self = this;
      let promise2;
      if(self.status == FULFILLED){
        return promise2 = new Promise(function(resolve,reject){
          setTimeout(function(){
            try{
              let x =onFulfilled(self.value);
              resolvePromise(promise2,x,resolve,reject);
            }catch(e){
              reject(e);
            }
          })
        });
      }
      if(self.status == REJECTED){
        return promise2 = new Promise(function(resolve,reject){
          setTimeout(function(){
            try{
              let x =onRejected(self.value);
              resolvePromise(promise2,x,resolve,reject);
            }catch(e){
              reject(e);
            }
          })
        });
      }
      if(self.status == PENDING){
       return promise2 = new Promise(function(resolve,reject){
         self.onResolvedCallbacks.push(function(){
             try{
               let x =onFulfilled(self.value);
               resolvePromise(promise2,x,resolve,reject);
             }catch(e){
               reject(e);
             }
         });
         self.onRejectedCallbacks.push(function(){
             try{
               let x =onRejected(self.value);
               resolvePromise(promise2,x,resolve,reject);
             }catch(e){
               reject(e);
             }
         });
       });
      }
    }
    

    promise的链式调用

    • 每次调用返回的都是一个新的Promise实例
    • 链式调用的参数通过返回值传递:即会将第一个then成功后,将他的返回值作为下一次成功的回调函数的参数
    • then可以使用链式调用的写法原因在于,每一次执行该方法时总是会返回一个Promise对象

    catch只是 promise.then(undefined, onRejected); 方法的一个别名而已。 也就是说,这个方法用来注册当promise对象状态变为Rejected时的回调函数
    catch原理就是只传失败的回调

    Promise.prototype.catch = function(onRejected){
      this.then(null,onRejected);
    }
    

    Promise.all 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then 方法

    Promise.all = function(promises){
     return new Promise(function(resolve,reject){
       let done = gen(promises.length,resolve);
       for(let i=0;i<promises.length;i++){
         promises[i].then(function(data){
           done(i,data);
         },reject);
       }
     });
    }
    

    Promise.race只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理

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

    别人提供 给你一个方法,需要你传入一个promise,但你只有一个普通的值,你就可以通过这个方法把这个普通的值(string number object)转成一个promise对象
    返回一个立刻成功的promise

    Promise.resolve = function(value){
      return new Promise(function(resolve){
        resolve(value);
      });
    }
    

    返回一个立刻失败的promise

    Promise.reject = function(reason){
      return new Promise(function(resolve,reject){
        reject(reason);
      });
    }
    

    相关文章

      网友评论

          本文标题:浅谈Promise之参照Promise/A+规范实现Promis

          本文链接:https://www.haomeiwen.com/subject/exldoxtx.html