Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。
ok,那么我们就开始写我们自己的Promise,我们先看看一段正常Promise的写法
- 一个promise只有三种状态,pending态,fulfilled态(完成态),rejected(拒绝态)
- 当promise处于pending态时,可能转化成fulfilled或者rejected
- 一旦promise的状态改成了fulfilled后,状态就不能再改变了,并且需要提供一个不可变的value
- 一旦promise的状态改成了rejected后,状态就不能再改变了,并且需要提供一个不可变的reason
好吧,我们总结了这么多规范特点,那么我们就用这些先来练练手
- promise必须要有一个then方法,用来访问它当前的value或者是reason
- 该方法接受两个参数onFulfilled(成功回掉函数),onRejected(失败回调函数) promise.then(onFulfilled, onRejected)
- 这两个参数都是可选参数,如果发现这两个参数不是函数类型的话,那么就忽略 比如 promise.then().then(data=>console.log(data),err=>console.log(err)) 就可以形成一个值穿透
- onFulfilled必须在promise状态改成fulfilled之后改成调用,并且呢promise内部的value值是这个函数的参数,而且这个函数不能重复调用
- onRejected必须在promise状态改成rejected之后改成调用,并且呢promise内部的reason值是这个函数的参数,而且这个函数不能重复调用
- onFulfilled和onRejected这两个方法必须要在当前执行栈的上下文执行完毕后再调用,其实就是事件循环中的微任务(setTimeout是宏任务,有一定的差异)
- onFulfilled和onRejected这两个方法必须通过函数调用,也就是说 他们俩不是通过this.onFulfilled()或者this.onRejected()调用,直接onFulfilled()或者onRejected()
- then方法可以在一个promise上多次调用,也就是我们常见的链式调用
- 如果当前promise的状态改成了fulfilled那么就要按照顺序依次执行then方法中的onFulfilled回调
- 如果当前promise的状态改成了rejected那么就要按照顺序依次执行then方法中的onRejected回调
- then方法必须返回一个promise(接下来我们会把这个promise称做promise2),类似于 promise2 = promise1.then(onFulfilled, onRejected);
- 如果呢onFulfilled()或者onRejected()任一一个返回一个值x,那么就要去执行resolvePromise这个函数中去(这个函数是用来处理返回值x遇到的各种值,然后根据这些值去决定我们刚刚then方法中onFulfilled()或者onRejected()这两个回调返回的promise2的状态)
- 如果我们在then中执行onFulfilled()或者onRejected()方法时产生了异常,那么就将promise2用异常的原因e去reject
- 如果onFulfilled或者onRejected不是函数,并且promise的状态已经改成了fulfilled或者rejected,那么就用同样的value或者reason去更新promise2的状态(其实这一条和第三条一个道理,也就是值得穿透问题)
我们又又又又又又总结了这么多,好吧不说了总结多少就开撸吧。
- resolvePromise这个函数呢会决定promise2用什么样的状态,如果x是一个普通值,那么就直接采用x,如果x是一个promise那么就将这个promise的状态当成是promise2的状态
- 判断如果x和promise2是一个对象,即promise2 === x,那么就陷入了循环调用,这时候promise2就会以一个TypeError为reason转化为rejected
- 如果x是一个promise,那么promise2就采用x的状态,用和x相同的value去resolve,或者用和x相同的reason去reject
- 如果x是一个对象或者是函数 那么就先执行let then = x.then
- 如果x不是一个对象或者函数 那么就resolve 这个x
- 如果在执行上面的语句中报错了,那么就用这个错误原因去reject promise2
- 如果then是一个函数,那么就执行then.call(x,resolveCallback,rejectCallback)
- 如果then不是一个函数,那么就resolve这个x
- 如果x是fulfilled态 那么就会走resolveCallback这个函数,这时候就默认把成功的value作为参数y传递给resolveCallback,即y=>resolvePromise(promise2,y),继续调用resolvePromise这个函数 确保 返回值是一个普通值而不是promise
- 如果x是rejected态 那么就把这个失败的原因reason作为promise2的失败原因reject出去
- 如果resolveCallback,rejectCallback这两个函数已经被调用了,或者多次被相同的参数调用,那么就确保只调第一次,剩下的都忽略掉
- 如果调用then抛出异常了,并且如果resolveCallback,rejectCallback这两个函数已经被调用了,那么就忽略这个异常,否则就用这个异常作为promise2的reject原因
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |