手写Promise笔记(下)

手写Promise笔记(上)我们已经得到了一个可用的手写Promise,不过过一阵子再来看,还是发现有很多地方不记得了,下面补上结合手写代码的Promise用法以及图解,加强记忆。

都是个人理解如果有错误,欢迎提出

Promise的基本用法

new myPromise((resolve, reject) => {
   resolve("成功");
}).then(
  msg => {
    console.log(msg);
  },
  error => {
    console.log(error);
  }
);

上面的代码是一个最普通的Promise用法then方法中对应的第一个是onFulfilled方法,第二个是onRejected方法。此时Promise的内部代码是同步的,resolve("成功")会直接更改,当前Promise的状态,在then方法会执行以下代码

      let promise =  new myPromise((resolve,reject) => {
         if(this.status === myPromise.PENDING) {
         ......
         }
         // 这里判断状态,必须是解决状态的情况才会执行onFulfilled函数,否则会出现状态没改变也执行的情况
         if(this.status === myPromise.FULFILLED) {
            setTimeout(() => {
               this.parse(promise,onFulfilled(this.value),resolve,reject)
            }, 0)
         }
         if(this.status === myPromise.REJECT) {
         ......
         }
      })
      return promise
   }

会把当前返回的promise以及传入的onFulfilled,这里的resolve以及reject都是新new出来的Promise自带的。在parse函数中会做以下的处理

   parse(promise,result,resolve,reject) {
      if(promise === result) {
         // 这里的判断用于限制Promise.then不能返回自身
         throw new TypeError('aaa')
      }
      // 使用try..catch也是为了捕获then中出现的错误,只有写了catch才会有错误信息输出
      try {
           // 这里的更改主要是针对Promise的内部函数的异步处理
           // 通过instanceof来判断result是否是通过myPromise实现的,从而确定是否是返回的Promise
           if (result instanceof myPromise) {
              // 如果是Promise的话,目的还是要改变Promise的状态,并且返回值
              // 此时 result 是一个Promise
              // 这里相当于重新执行了一次返回的Promise,递归
              result.then(resolve,reject)
           } else {
              // 普通值直接返回
              resolve(result)
           }
        } catch (error) {
           // then的异步处理中出现error就交给onRejected处理
           // 同时这里的处理函数从onRejected改为reject,相当于把错误代码交给了
           // 最后一个then来处理
           reject(error)
        }
   }
parse函数

这样上面那个最简单的Promise的使用就相当于

  1. resolve("成功"),变更当前Promise的状态为fulfilled,函数内的setTimeout异步函数挂起
  2. 进入then方法,此时的状态为fulfilled,所以进入this.parse(promise,onFulfilled(this.value),resolve,reject)代码,因为当前的onFulfilled方法为一个简单的打印,不是返回Promise,那么就直接使用新返回的Promiseresolve方法执行,此时的this.value='成功',那么就相当于调用msg => {console.log(msg)},之前resolve挂起的定时器异步任务开始执行,callback为空,所以无结果。
    相当于then中最后执行的结果如下
let promise = new myPromise((resolve,reject) => {
  setTimeout(() => {
    this.parse(promise,onFulfilled(this.value),resolve,reject)
   }, 0)
})
return promise 

这里我不太清楚,返回的Promiseparse之间的运行关系,希望以后有机会找大佬请教下

Promise内的异步操作

假设Promise内的操作是异步的,这种情况还是挺常见的,例如异步获取数据之类的。

let p = new myPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("成功")
  }, 0);
}).then(
  msg => {
    console.log('promise' + msg);
  },
  error => {
    console.log(error);
  }
)
console.log('我先执行')

输出的结果是我先执行---promise成功
这里就会涉及到JavaScript中的EvenLoop,直接看手写代码,这里只解释成功的部分,失败的部分原理一样。
在resolve方法中

   resolve(value) {
      // 这里需要增加一个判断,如果当前Promise的状态为pending的时候,才能进行状态更改和处理
      if(this.status === myPromise.PENDING) {
        this.status = myPromise.FULFILLED
        this.value = value
        setTimeout(() => {
           this.callbacks.map(callback => {
            callback.onFulfilled(value)
         })
        })
      }
   }

在then方法中

if(this.status === myPromise.PENDING) {
            this.callbacks.push({
               onFulfilled: value => {
                  this.parse(promise,onFulfilled(value),newresolve,newreject)
               },
               onRejected: reason => {
                  this.parse(promise,onRejected(reason),newresolve,newreject)
               },
            })
         }

如果Promise本体中的方法是异步的,当函数开始的时候,内部的定时器挂起,此时定时器是一个宏任务,异步执行,之后执行到then方法,方法内判断到当前的状态pending,那么就会将传入的onFulfilledonRejected通过parse处理后保存起来。
此轮同步循环结束,执行之前挂起的定时器,开始循环callback中的onFulfilled方法,并且执行,完成异步输出的结果。

Promise的链式调用

Promise链式调用的前提就是前一个then返回的是一个Promise,并且下一个then对应的状态总是成功的

let p = new myPromise((resolve, reject) => {
    // resolve("成功")
    reject("失败")
}).then(
  msg => {
    console.log('promise' + msg);
    return '成功22'
  },
  error => {
    console.log(error);
    return '失败22'
  }
)
.then(
  msg => {
    console.log('promise2' + msg);
  },
  error => {
    console.log(error);
  }
)

上面的代码无论第一个使用的是resolve还是reject,第二个then都是走console.log('promise2' + msg)


上面例子代码的运行流程

  1. 首先new myPromise的时候首先同步执行reject("失败"),此时当前Promise的状态为rejected
  2. 进入第一个then,因为判断当前状态时rejected,会执行
if(this.status === myPromise.REJECT) {
            setTimeout(() => {
               this.parse(promise,onRejected(this.value),newresolve,newreject)
            }, 0)
         }

此时setTimeout挂起第一个异步程序,这里我们把它叫做定时1

  1. 然后第一个then返回了一个新的Promise,叫做newPromise,并且通过他连接上下一个then
  2. 在这个newPromise中,resolvereject函数都没有执行,所以当前的newPromise的状态还是pending,在then中判断状态,就把第二个then中的两个函数通过parse处理后存起来。
  3. 以上同步任务都处理完成了,会进入Promise中的定时1,开始执行其中的异步程序。
 setTimeout(() => {
   this.parse(promise,onRejected(this.value),newresolve,newreject)
 }, 0)

这里的newresolvenewreject是返回的newPromise中的resolvereject函数,在parse会判断第一个then返回的onRejected是不是Promise,如果不是就用传入的newresolve来执行
相当于执行了

newresolve(msg => {
    console.log('promise' + msg);
    return '成功22'
  })
  1. newPromise的内部resolve执行的就是resolve('成功22')接受'成功22'这个参数,并且更改newPromise的状态为resolved,此时newPromise的之前保存函数callbacks也不为空了,循环执行之前保存的onFulfilled函数
  2. 上面的过程就实现了then的链式调用

then中返回一个Promise的情况

如果 then 返回的是一个promise,那么需要等这个promise,那么会等这个promise执行完,promise如果成功,就走下一个then的成功,如果失败,就走下一个then的失败。

let p2 = new myPromise((resolve,reject) => {
  reject('失败了')
})
new myPromise((resolve, reject) => {
    resolve("成功")
    // reject("失败")
}).then(
  msg => {
    console.log('promise' + msg);
    return p2
  },
  error => {
    console.log(error);
    return '失败22'
  }
)
.then(
  msg => {
    console.log('promise2' + msg);
  },
  error => {
    console.log('then2'+ error);
  }
)


这里主要通过parse来进行操作的,可以看最上面parse的全部代码这里只放部分了

if (result instanceof myPromise) {
  result.then(resolve,reject) 
} 

这里传入的result就是前一个then方法的onFulfilled(this.value)或者onRejected(this.value)

msg => {
    console.log('promise' + msg);
    return p2
  },

对应到上面代码就是这段,返回的p2,作为result传入了parse,再通过instanceof来判断是否是由myPromise创建的,就是判断是不是一个Promise。
之后直接调用了p2.then(),所以下一个then相当于是p2.then().then()这种形式,第一个then发生值传递,直接给第二个then,且p2中是使用reject方法,所以是走onRejected()方法输出

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

推荐阅读更多精彩内容

  • Promise学习(上): 资料: JavaScript Promise迷你书 原著:azu / 翻译:liubi...
    你隔壁的陌生人阅读 557评论 0 1
  • 1 什么是 Promise Promise 是前端流行的异步编程解决方案,而Promise/A+ 是一组关于 Pr...
    秀夫Longer阅读 558评论 0 0
  • 1. promise要解决的问题: 脑筋急转弯:把牛关进冰箱里,要分几步? 很显然,这三个操作不能颠倒顺序,否则任...
    月上秦少阅读 1,565评论 0 3
  • 什么叫promise? Promise对象可以理解为一次执行的异步操作,使用promise对象之后可以使用一种链式...
    98b8dc01512b阅读 288评论 0 0
  • Promise 对象 Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函...
    neromous阅读 8,698评论 1 56