实现符合 Promise/A+ 规范的Promise

实现一个符合 Promise/A+ 规范的 MyPromise,并实现 resolve、reject、all、race等静态方法。

promise

  1. 创建Promise 方法
  2. Promise 接收一个 executor 回掉函数
  3. Promise 三个状态
  • pedding
    • 可以变为 fulfilled 成功态 或者 rejected 失败态
  • fulfilled
    • 不可改变的成功态
  • rejected
    • 不可改变失败态
  1. onResolvedCallbacks和onRejectedCallbacks
    • 分别存储成功 成功和失败的回调函数
  2. resolve
    • promise专向成功态调用的函数,接收value参数
  3. reject
    • promise转向失败态调用的函数,接受reason参数
function  Promise(executor) {
    let self = this;
    self.status = 'pending';
    //存放成功回调的数组
    self.onResolvedCallbacks =[];
    //存放失败回调的数组
    self.onRejectedCallbacks =[];
    
    function resolve(value) {
        if(self.status == 'pending'){
            self.status = 'fulfilled';
            self.value = value;//成功后得到一个值,这个值不能改
            self.onResolvedCallbacks.forEach(cb=>cb(self.value))//

        }
    }
    function reject(reason) {
        if(self.status == 'pending'){
            self.status = 'rejected';
            self.value = reason;
            self.onRejectedCallbacks.forEach(cb=>cb(self.value))
        }
    }
    try{
        executor(resolve,reject)
    }catch (e){
        //如果函数执行失败了,reject这个promise
        reject(e)
    }
}

Promise.prototype.then

链式调用返回一个新的Promise,将第一次的返回值,作为下一次成功回掉函数的参数

  1. onFulfilledonRejected
    • 一个promise.then方法接收两个参数onFilfiledonRejected
    • 如果成功和失败的回调没有传,则表示这个then没有任何逻辑,只会把值往后抛
  2. onFulfilled
    • 成功时调用
    • 并把成功的结果传递给onFulfilled
    • 不能调用多次
  3. onRejected
    • 失败时调用
    • 并把失败的结果传递给onRejected
    • 不能调用多次
  4. then会调用多次,之后返回一个新的promise
    • promise2 = promise1.then(onFulfilled, onRejected)
    • 如果 onFulfilledonRejected返回x解析promise 执行 resolvePromise方法
Promise.prototype.then = function (onFulfilled,onRejected) {
    onFulfilled = typeof onFulfilled == 'function'?onFulfilled:value=>value;
    onRejected = typeof onRejected == 'function'?onRejected:reason=>{throw reason};
    let self = this;
    let promise2;
    //当前promise已经是成功态了,onFulfilled直接取值
    if(self.status == 'fulfilled'){
        return promise2 = new Promise(function (resolve,reject) {
            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) {
           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);
                }
            });
        });
    }

};

The Promise resolvePromise 解析方法

  1. 如果x===当前promise2 不能返回当前Promise,那么会抛出错误 new TypeError('循环引用')
  2. x是一个Promise
    • 当前promise2等待x完成,x有可能也是一个Promise 执行resolvePromise()
  3. x 如果不是对象(不包括 null)或者函数,执行 resolve(x)
  4. 获取 x.then 赋值给 then
    • then 如果是 function
      • 把 x做为 this 调用then,第一个参数是 resolvePromise2,第二个参数是 rejectPromise2
      • resolvePromise2rejectPromise2只有第一次调用有效
      • resolvePromise2参数为 y,执行 resolvePromise(promise, y, resolve, reject)
    • then 如果不是 function
      • 执行resolve(x)
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'))){
   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);
  }
}

Promise.prototype.catch

  1. 只传失败的回掉
Promise.prototype.catch = function(onRejected){
  this.then(null,onRejected);
}

Promise.all

  1. 接收Promise数组,全部完成才会成功,有一个失败,整个Promise失败
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);
   }
 });
}

Promise.race

  1. 接收Promise数组,一个成功就成功了,一个失败就失败了
Promise.race = function(promises){
  return new Promise(function(resolve,reject){
    for(let i=0;i<promises.length;i++){
      promises[i].then(resolve,reject);
    }
  });
}

Promise.resolve

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

Promise.reject

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

源码

参考资料

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