2018-03-18

Promise初次尝试

注意:判断一个变量是不是Promise,有三项主要的特征可作为参考。

  • 该变量有三种状态pendingfulfilledrejected
  • 该变量 含有then方法
  • 该变量含有Promise Resolution Procedure (promise的状态转换处理方法)。

1.promise基本使用

let p = new Promise((resolve,reject)=>{
  let x = Math.random();
  console.log(x);
  if (x > .5) {
    resolve('666');
  } else {
    reject('GG思密达');
  }
});

p.then((value)=>{ //绑定成功时的回调函数
  console.log('fulfilled:',value); 
},(reason)=>{ //绑定失败时的回调函数
  console.log('rejected:',reason); 
});

当Promise处于pending状态时,它可能转换为fulfilled或则rejected状态。

当Promise处于fulfilled状态时,它不再能转换为其它状态 且 它必须有一个值,这个值不能被更改。

当promise处于rejected时,它不再能转换为其它状态 且 它必须有一个理由,这个理由不能被更改。

2.promise的基本实现

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

function Promise(executor){
  let self = this; //缓存下
  self.value = undefined; //用来存放value和reason,因为promise只会处于一种状态故可只用一个变量来表示。
  self.status = PENDING; //将初始状态设置为pending
  self.onFulfilledCallbacks = []; //用来存放所有成功的回调函数
  self.onRejectedCallbacks = []; //用来存放所有失败的回调函数

  try{
    executor(resolve,reject); //调用执行函数,将resolve和reject方法作为参数传入
  }catch (e){
    reject(e); //若执行函数中存在异常直接用抛出的值来拒绝promise
  }
  //-----------------------------------------------------------------------------------------------------------
  function resolve(value){ //此方法会随着executor传入而传入
    setTimeout(function(){
      if(self.status === PENDING){ //确保状态只会改变一次
        self.status = FULFILLED; //改变状态
        self.value = value; //赋予一个值
        self.onFulfilledCallbacks.forEach(cb => cb(self.value)); //2.2.2. //2.2.6.
      }
    })
  }
  function reject(reason){
    setTimeout(function(){
      if(self.status === PENDING){
        self.status = REJECTED;
        self.value = reason;
        self.onRejectedCallbacks.forEach(cb => cb(self.value));
      }
    })
  }
}

/*我们可以发现最终转换状态时通过Promise内部的两个方法resolve和reject,这个两个方法是在什么时候传入的呢?一个函数的参数查找,是从调用这个函数时所处的作用域开始查找的。new Promise传入的executor,是参数也是对executor函数的定义,此时executor的resolve和reject为形参。我们new Promise的时候,会执行构造函数Promise内的代码,也就是在这时executor被执行,而executor此时所处的作用域是在Promise构造函数内部,resolve和reject方法作为实参被传入。*/

2.1. then方法

  • 一个promise必须提供一个then方法来使用它将要或则说已经被赋予的 value 或则 reason,一个promise的then方法接收两个参数,then中的参数皆为可选参数,如果onFulfilled或则说onRejected不是一个函数,那么将会被忽略。
  • 如果onFulfilled是一个函数,它必须在promise状态转换为fulfilled时候就被调用,并且promise被赋予的value会成为这个函数(onFulfilled)的第一个参数。onFulfilled不能在promise状态转化为fulfilled前就调用onFulfilled函数不能重复调用
  • 如果onRejected是一个函数,它必须在promise状态转换为rejected时候就被调用,并且promise被赋予的reason会成为这个函数(onRejected)的第一个参数。
    onRejected不能在promise状态转化为rejected前就调用
    onRejected函数不能重复调用
  • 当一个promise转化为fulfilled状态,所有onFulfilled callback会按照回调函数通过then添加时的顺序而执行。当一个promise转化为rejected状态,所有onRejected callback会按照回调函数通过then添加时的顺序而执行。
  • 如果onFulfilled或onRejected回调函数中返回了一个值,假定为x,那么调用一个 promise解析方法。
    如果onFulfilled或者onRejected抛出了一个 exception(异常) e , promise2 必须以这个e作为reason来拒绝promise,使其状态改变为rejected。
    如果onFulfilled不是一个函数且 promise1 的状态为fulfilled,promise2必须以 promise1 的值来fulfilled。
    如果onRejected不是一个函数且 promise1 的状态为rejected,promise2必须以 promise1 的理由来rejected。

3.promise的中度实现

function Promise(){
    ...
    function resolve(value){ 
    setTimeout(function(){ 
      if(self.status === PENDING){
        self.status = FULFILLED; 
        self.value = value; 
        self.onFulfilledCallbacks.forEach(cb => cb(self.value)); 
      }
    })
  }
  function reject(reason){
    setTimeout(function(){
      if(self.status === PENDING){ 
        self.status = REJECTED;
        self.value = reason;
        self.onRejectedCallbacks.forEach(cb => cb(self.value));
      }
    })
  }
}

Promise.prototype.then = function (onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};

  let self = this,
    promise2;

  if(self.status === PENDING){
  
    return promise2 = new Promise(function(resolve,reject){
      self.onFulfilledCallbacks.push((value)=>{
        try{
          let x = onFulfilled(value);
          resolvePromise(promise2,x,resolve,reject);
        }catch (e){
          reject(e); 
        }
      });
      self.onRejectedCallbacks.push((reason)=>{
        try{
          let x= onRejected(reason);
          resolvePromise(promise2,x,resolve,reject);
        }catch (e){
          reject(e);
        }
      });
    });
  }
};

3.1 Promise状态解析方法(promise resolution procedure)

let x= onRejected(reason);resolvePromise(promise2,x,resolve,reject);

  • Promise状态解析方法的作用是将then时返回的promise2的状态改变并赋予其vlaue/reason。
  • 如果 x 是一个thenable,那么该方法将试图将以 x 的状态来改变 promise2 的状态否则就将 promise2 改成 fulfilled 状态,并且value即为 x 的值

3.1.1. 如果 promise2 和 x 是引用关系,则抛出一个 TypeError 做为理由来 reject promise2。
3.1.2. 如果 x 是一个promise ,让promise2采用它的状态。

如果 x 处于pending,promise2 必须保持pending直到 x 转换为 fulfilled或则rejected。
如果 x 是 fulfilled状态,让promise2也为fulfilled,并且让promise2的value为x的value。
如果 x 是 rejected状态,让promise2也为rejected,并且让promise2的value为x的reason。

3.1.3. 如果 x 是一个对象或则函数

Let then be x.then
如果检索 x.then 时候抛出了一个异常e,那么以这个 e来 rejecte promise2。
如果 then 是一个函数,用x作为this,resolvePromise作为第一个参数,rejectPromise作为第二个参数来 call它。

如果resolvePromise被调用,循环调用 promise状态解析方法(原本的x替换为调用resolvePromise传入的参数,假定为y)。
如果rejectPromise被调用,则reject Promise2,reason为调用rejectPromise传入的参数
如果resolvePromise 和 rejectPromise 同时被调用或则多次调用,那么第一个调用的拥有优先权,其它的会被忽略。
如果调用 then 的时候抛出了一个异常 e

如果 resolvePromise 或 rejectPromise 已经被调用,则忽略它。
否则,则用这个e来 reject promise2。

3.1.4如果then不是一个函数,则用x来fulfilledpromise2

Promise.catch的基本实现

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

Promise.all的基本实现

Promise.all = function(promises){
    return new Promise((resolve,reject)=>{
        let result = [],
            count = 0;

        function done(i,data){
            result[i] = data;
            if(++count===promises.length){
                resolve(result);
            }
        }
        for(let i=0;i{
                done(i,value);
            },(reason)=>{
                reject(reason);
            });
        }
    });
}

Promise.promisify的基本实现

Promise.promisify = function(fn){
    return function(...args){
        return new Promise((resolve,reject)=>{
            fn.apply(null,[...args,function(err,data){
                err?reject(err):resolve(data);
            }]);
        });
    }
}

Promise.promisifyAll的基本实现

Promise.promisifyAll = function(obj){
    for(var attr in obj){
        if(obj.hasOwnProperty(key)&&typeof obj[attr]==='function'){
            obj[attr+'Async'] = Promise.promisify(obj[attr]);
        }
    }
}

Promise.race的基本实现

Promise.race = function(promises){
    return new Promise((resolve,reject)=>{
        for(let i=0;i

你可能感兴趣的:(2018-03-18)