Promise技术探究

1.promise简介

  1.1    

          Promise本意是承诺,在程序中的意思就是承诺我过一段时间后会给你一个结果。 什么时候会用到过一段时间?答案是异步操作,异步是指可能比较长时间才有结果的才做。

        Promise表示一个异步操作的最终结果。与Promise最主要的交互方法是通过将函数传入它的then方法从而获取得Promise最终的值或Promise最终最拒绝(reject)的原因。

1.2  Promise状态

一个Promise必须处在其中之一的状态:pending, fulfilled 或 rejected.

如果是pending状态,则promise:

可以转换到fulfilled或rejected状态。

如果是fulfilled状态,则promise:

不能转换成任何其它状态。

必须有一个值,且这个值不能被改变。

如果是rejected状态,则promise可以:

不能转换成任何其它状态。

必须有一个原因,且这个值不能被改变。

”值不能被改变”指的是其identity不能被改变,而不是指其成员内容不能被改变。

1.3 then 方法

一个Promise必须提供一个then方法来获取其值或原因。

Promise的then方法接受两个参数:

promise.then(onFulfilled, onRejected)

onFulfilled 和 onRejected 都是可选参数:如果onFulfilled不是一个函数,则忽略之。如果onRejected不是一个函数,则忽略之。

如果onFulfilled是一个函数:它必须在promise fulfilled后调用, 且promise的value为其第一个参数。

它不能在promise fulfilled前调用。不能被多次调用。

如果onRejected是一个函数,它必须在promise rejected后调用, 且promise的reason为其第一个参数。

它不能在promise rejected前调用。不能被多次调用。

onFulfilled 和 onRejected 只允许在 execution context 栈仅包含平台代码时运行. 

onFulfilled 和 onRejected 必须被当做函数调用 (i.e. 即函数体内的 this 为undefined). 

对于一个promise,它的then方法可以调用多次.

当promise fulfilled后,所有onFulfilled都必须按照其注册顺序执行。

当promise rejected后,所有OnRejected都必须按照其注册顺序执行。

then 必须返回一个promise 

promise2 = promise1.then(onFulfilled, onRejected);

如果onFulfilled 或 onRejected 返回了值x, 则执行Promise 解析流程[[Resolve]](promise2, x).

如果onFulfilled 或 onRejected抛出了异常e, 则promise2应当以e为reason被拒绝。

如果 onFulfilled 不是一个函数且promise1已经fulfilled,则promise2必须以promise1的值fulfilled.

如果 OnReject 不是一个函数且promise1已经rejected, 则promise2必须以相同的reason被拒绝.

2.使用promise

let promise = new Promise((resolve, reject) => {

        setTimeout(function(){

                let num =Math.random();

                  if(num<.5){

                        resolve(num);

                  }else{

                        reject('失败');

                  }

        })

});

promise.then(Fulfilled,Rejected)

构造一个Promise实例需要给Promise构造函数传入一个函数。

传入的函数需要有两个形参,两个形参都是function类型的参数。

第一个形参运行后会让Promise实例处于resolve状态,所以我们一般给第一个形参命名为resolve,使 Promise 对象的状态改变成成功,同时传递一个参数用于后续成功后的操作

第一个形参运行后会让Promise实例处于reject状态,所以我们一般给第一个形参命名为reject,将 Promise 对象的状态改变为失败,同时将错误的信息传递到后续错误处理的操作

3 .自己实现promise

const PENDING = 'pending';//初始态

const FULFILLED =  'fulfilled';//成功态

const REJECTED =  'rejected';//失败态

function Promise(executor){

  let self = this;//先缓存当前promise实例

  self.status = PENDING;//设置状态

  //定义存放成功的回调的数组

  self.onResolvedCallbacks = [];

  //定义存放失败回调的数组

  self.onRejectedCallbacks = [];

  //当调用此方法的时候,如果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){ 

    setTimeout(function(){

      //如果是初始态,则转成失败态

      if(self.status == PENDING){

        self.status = REJECTED;

        self.value = reason;//失败的原因给了value

        self.onRejectedCallbacks.forEach(cb=>cb(self.value));

      }

    });

  }

  try{

    //因为此函数执行可能会异常,所以需要捕获,如果出错了,需要用错误 对象reject

    executor(resolve,reject);

  }catch(e){

    //如果这函数执行失败了,则用失败的原因reject这个promise

    reject(e);

  };

}

function resolvePromise(promise2,x,resolve,reject){

  if(promise2 === x){

    return reject(new TypeError('循环引用'));

  }

  let called = false;//promise2是否已经resolve 或reject了

  if(x instanceof Promise){

    if(x.status == PENDING){

      x.then(function(y){

        resolvePromise(promise2,y,resolve,reject);

      },reject);

    }else{

      x.then(resolve,reject);

    }

  //x是一个thenable对象或函数,只要有then方法的对象,

  }else if(x!= null &&((typeof x=='object')||(typeof x == 'function'))){

    //当我们的promise和别的promise进行交互,编写这段代码的时候尽量的考虑兼容性,允许别人瞎写

  try{

    let then = x.then;

    if(typeof then == 'function'){

      //有些promise会同时执行成功和失败的回调

      then.call(x,function(y){

        //如果promise2已经成功或失败了,则不会再处理了

          if(called)return;

          called = true;

          resolvePromise(promise2,y,resolve,reject)

      },function(err){

        if(called)return;

        called = true;

        reject(err);

      });

    }else{

      //到此的话x不是一个thenable对象,那直接把它当成值resolve promise2就可以了

      resolve(x);

    }

  }catch(e){

    if(called)return;

    called = true;

    reject(e);

  }

  }else{

    //如果X是一个普通 的值,则用x的值去resolve promise2

    resolve(x);

  }

}

//onFulfilled 是用来接收promise成功的值或者失败的原因

Promise.prototype.then = function(onFulfilled,onRejected){

  //如果成功和失败的回调没有传,则表示这个then没有任何逻辑,只会把值往后抛

  onFulfilled = typeof onFulfilled == 'function'?onFulfilled:function(value){return  value};

  onRejected = typeof onRejected == 'function'?onRejected:reason=>{throw reason};

  //如果当前promise状态已经是成功态了,onFulfilled直接取值

  let self = this;

  let promise2;

  if(self.status == FULFILLED){

    return promise2 = new Promise(function(resolve,reject){

      setTimeout(function(){

        try{

          let x =onFulfilled(self.value);

          //如果获取到了返回值x,会走解析promise的过程

          resolvePromise(promise2,x,resolve,reject);

        }catch(e){

          //如果执行成功的回调过程中出错了,用错误原因把promise2 reject

          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);

          //如果获取到了返回值x,会走解析promise的过程

          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);

        }

    });

  });

  }

}

module.exports =Promise;

4 自己实现promise.all

function gen(times,cb){

  let result = [],count=0;

  return function(i,data){

    result[i] = data;

    if(++count==times){

      cb(result);

    }

  }

}

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);

                    }

         });

}

5. 自己实现 Promise.race

Promise.race =function(promises){

    return new Promise(function(resolve,reject){

            for(let i=0;i<promises.length;i++){

                promises[i].then(resolve,reject);

              }

    });

}

6. 自己实现 Promise.resolve

Promise.resolve =function(value){

        return new Promise(function(resolve){

                resolve(value);

          });

}


7. 自己实现 Promise.resolve

Promise.reject =function(reason){

           return new Promise(function(resolve,reject){

                reject(reason);

          });

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容