浅谈Promise之按照Promise/A+规范实现Promise类

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

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);
  });
}
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值