手写Promise思维逻辑
思维流程
- 在使用promise时, 需要通过new关键字去new一个promise对象,由此可见, promise其实是一个class类
- 在执行这个类时,需要传递一个回调函数(执行器executor), 执行器会立即执行
- promise当中有三种状态 pending fulfilled rejected 等待 成功 失败,并且状态确定后就不可改变
- pending ==> fulfilled
- pending ==> rejected
- resolve(将状态变为fulfilled) 和 reject是用来更改状态的(将状态变为rejected)
- 传给resolve的值就是执行成功后的值, 传给reject的值就是执行失败的原因
- promise可以调用then方法, 在执行then中的方法时判断promise的状态, 如果状态是fulfilled,则需要调用成功回调, 如果状态是rejected,则需要调用失败回调, then方法是原型对象上的一个方法
- then成功回调有一个参数表示成功的值, 失败回调有一个参数表示失败的原因
- (1~7具体实现请参考: promise基本逻辑实现)
- 因为创建promise实例对象后, 传递的执行器会立即执行, 当执行器执行时,如果发现执行器中有异步代码, 这个时候,主线程中的代码是不会等待异步代码执行完毕再执行,而是会立即执行,
所以then方法立刻执行, 而then方法中去判断了promise的状态, 由于当前这个promise并没有执行resolve或reject, 所以当前promise的状态一定是pending,
而到现在为止,Mypromise的then方法当中没有判断pending的状态, 那么在添加promise的异步处理时,在then中去判断pending - (具体实现请参考: promise异步处理逻辑实现) - promise对象下的then方法是可以多次被调用的, 当then方法被多次调用的时候, 每一个then方法中传递的回调函数都是要被多次执行的,而这种情况也要分两种情况: 回调是同步代码, 回调是异步代码
- 同步函数: 到此为止已不需要为同步代码在进行请他处理
- 异步代码: 每一个then方法中的每一个回调函数都要把它储存起来,当状态变为成功或失败时再去依次调用
- (具体实现请参考: 实现then方法多次调用)
- then方法是可以被链式调用的, 后面then方法的回调函数拿到的值是上一个then方法的回调函数的返回值
- 如果要实现then方法的链式调用, 那么每一个then方法都应该<font color=’#FF0000’返回一个promise对象
- 如何把上一个then方法回调函数的返回值传递给下一个then方法的回调函数
- 返回的是一个普通值
- 返回的是一个promise对象, 查看这个promise对象所返回的结果, 再根据返回的结果,去调用resolve还是reject
- (具体实现请参考: 实现then方法的链式调用)
- 在then方法中不可以返回当前then方法所返回的promise对象, 并捕捉promise执行中的异常
- 在then方法中不可以返回当前then方法所返回的promise对象, 如果返回的话,会导致当前promise的循环调用
- (具体实现请参考: promise链式调用识别自身并捕捉promise执行中的异常)
- then方法的两个参数成功和失败回调都是可选参数
- Promise.all方法
- 用来解决异步并发问题, 允许我们通过异步代码调用的顺序得到异步代码执行的结果
- 通过类.all的方法来调用, 所以all方法是一个静态方法
- promise.resolve
- promise.resolve会将给定的值转换成promise对象
- promise.finally
- 无论promise方法返回的是成功还是失败, finally中的回调函数都会被执行一次
- 可以链式调用then方法拿到这个promise对象最终返回的结果
- promise.catch
- 失败回调
- (12~16具体实现请参考: 将then方法变为可选参数, promise.all, promise.resolve, promise.finally, promise.catch)
promise基本逻辑实现
// 声明promise的状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject) // 执行器立即执行
}
status = PENDING //promise的状态
value = undefined; // 用来储存成功的值
reason = undefined; //用来储存失败原因
// 因为在执行器中调用resolve 或 reject时是直接调用的, 如果写普通的function函数,那么resolve和reject的this指向会是window或是undefined
// 定义为箭头函数是为了让他们的this指向为promise的实例对象
resolve = value => {//添加resolve属性用来改变状态
if (this.status !== PENDING) return //判断状态是否更改过, 如果更改了,那么就不再向下执行, reject同理
// 将状态更改为成功
this.status = FULFILLED
this.value = value //储存成功的值, 方便在then中取到
}
reject = reason => {//添加reject属性用来改变状态
if (this.status !== PENDING) return
// 将状态更改为失败
this.status = REJECTED
this.reason = reason//储存失败的值, 方便在then中取到
}
then (successCallBack, failCallBack) {
if (this.status === FULFILLED) { //如果状态是fulfilled,则需要调用成功回调, 并传递成功的值
successCallBack(this.value)
} else if (this.status === REJECTED) { // 如果状态是rejected,则需要调用失败回调, 并传递失败的原因
failCallBack(this.reason)
}
}
}
promise异步处理逻辑实现
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject)
}
status = PENDING
value = undefined;
reason = undefined;
// 储存成功回调
successCallBack = undefined
// 储存失败回调
failCallBack = undefined
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// 判断成功回调是否存在, 如果存在就调用并将成功的值传回去
this.successCallBack instanceof Function && this.successCallBack(this.value)
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// 判断失败回调是否存在, 如果存在就调用并将失败原因传回去
this.failCallBack instanceof Function && this.failCallBack(this.reason)
}
then (successCallBack, failCallBack) {
if (this.status === FULFILLED) {
successCallBack(this.value)
} else if (this.status === REJECTED) {
failCallBack(this.reason)
} else { //如果走到了else, 就说明该promise的状态是pending, 因为现在并不知道promise是成功还是失败,所以将successCallBack和failCallBack临时储存起来, 当异步代码执行时再去调用成功或失败回调
this.successCallBack = successCallBack
this.failCallBack = failCallBack
}
}
}
实现then方法多次调用
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject)
}
status = PENDING
value = undefined;
reason = undefined;
// 为了储存多个成功回调和失败回调, 因此successCallBack和failCallBack要为数组
successCallBack = []
failCallBack = []
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// while循环依次调用储存的成功回调
while (this.successCallBack.length) this.successCallBack.shift()(this.value)
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// while循环依次调用储存的失败回调
while (this.successCallBack.length) this.successCallBack.shift()(this.reason)
}
then (successCallBack, failCallBack) {
if (this.status === FULFILLED) {
successCallBack(this.value)
} else if (this.status === REJECTED) {
failCallBack(this.reason)
} else {
// 将成功回调和失败回调储存起来
if (successCallBack instanceof Function) this.successCallBack.push(successCallBack)
if (failCallBack instanceof Function) this.failCallBack.push(failCallBack)
}
}
}
实现then方法的链式调用
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject)
}
status = PENDING
value = undefined;
reason = undefined;
successCallBack = []
failCallBack = []
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
while (this.successCallBack.length) this.successCallBack.shift()(this.value)
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
while (this.successCallBack.length) this.successCallBack.shift()(this.reason)
}
then (successCallBack, failCallBack) {
// 既然要返回一个promise对象, 那么就要创建一个promise对象
let newPromise = new MyPromise((resolve, reject) => { //promise中执行器是立即执行的, 而之前then方法中的代码也需要立即执行,所以将这些代码放入执行器中
// 想要将上一个then方法的返回值传递给下一个then方法, 而每一个then方法都会返回一个promise对象,而这个promise对象就是newPromise, 那么只要调用newPromise的resolve方法就可以把成功的值传递给下一个then方法
if (this.status === FULFILLED) {
let successInfo = successCallBack(this.value) //在这里调用了成功回调, 就可以在这里拿到这个成功回调的返回值
resolvePromise(successInfo, resolve, reject)
} else if (this.status === REJECTED) {
failCallBack(this.reason) //在这里调用了失败回调, 就可以在这里拿到这个失败回调的失败原因
} else {
if (successCallBack instanceof Function) this.successCallBack.push(successCallBack)
if (failCallBack instanceof Function) this.failCallBack.push(failCallBack)
}
})
return newPromise
}
}
function resolvePromise (c, resolve, reject) {
// 判断是否为MyPromise的实例对象, 如果不是,那它就是一个普通值
if (c instanceof MyPromise) {
c.then(resolve, reject)
} else {
// 普通值
resolve(c)
}
}
promise链式调用识别自身并捕捉promise执行中的异常
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject)
}
status = PENDING
value = undefined;
reason = undefined;
successCallBack = []
failCallBack = []
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
while (this.successCallBack.length) this.successCallBack.shift()(this.value)
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
while (this.successCallBack.length) this.successCallBack.shift()(this.reason)
}
then (successCallBack, failCallBack) {
let newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => { // 因为单单的resolvePromise是同步代码, 在resolvePromise执行时, newPromise正在创建实例中, 是获取不到newPromise的,
// 所以用setTimeOut将newPromise变为异步代码, 在newPromise市里完成后就可以获取到newPromise
let successInfo = successCallBack(this.value)
resolvePromise(newPromise, successInfo, resolve, reject) // 将newPromise作为参数传递给resolvePromise方法, 用来判断then方法中是否返回了自己本身的promise
}, 0)
} else if (this.status === REJECTED) {
failCallBack(this.reason)
} else {
if (successCallBack instanceof Function) this.successCallBack.push(successCallBack)
if (failCallBack instanceof Function) this.failCallBack.push(failCallBack)
}
})
return newPromise
}
}
function resolvePromise (newPromise, c, resolve, reject) {
if (newPromise === c) { //判断promise是否返回了自己, 并抛出异常
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (c instanceof MyPromise) {
c.then(resolve, reject)
} else {
resolve(c)
}
}
将then方法变为可选参数, promise.all, promise.finally , promise.catch
class MyPromise {
constructor (executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING
value = undefined;
reason = undefined;
successCallBack = []
failCallBack = []
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
while (this.successCallBack.length) this.successCallBack.shift()()
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
while (this.failCallBack.length) this.failCallBack.shift()()
}
then (successCallBack, failCallBack) {
successCallBack = successCallBack instanceof Function ? successCallBack : value => value //判断successCallBack是否为true 如果为true 则执行successCallBack, 否则将返回值再传递给后面的then方法
failCallBack = failCallBack instanceof Function ? failCallBack : reason => { throw reason } //判断failCallBack是否为true 如果为true 则执行failCallBack, 否则将失败原因再传递给后面的then方法
let newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let successInfo = successCallBack(this.value)
resolvePromise(newPromise, successInfo, resolve, reject)
}catch (e) {
this.reject(e)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let failInfo = failCallBack(this.reason)
resolvePromise(newPromise, failInfo, resolve, reject)
}catch (e) {
this.reject(e)
}
}, 0)
} else {
if (successCallBack instanceof Function) this.successCallBack.push(() => {
setTimeout(() => {
try {
let successInfo = successCallBack(this.value)
resolvePromise(newPromise, successInfo, resolve, reject)
}catch (e) {
this.reject(e)
}
}, 0)
}) //
if (failCallBack instanceof Function) this.failCallBack.push(() => {
setTimeout(() => {
try {
let failInfo = failCallBack(this.reason)
resolvePromise(newPromise, failInfo, resolve, reject)
}catch (e) {
this.reject(e)
}
}, 0)
})
}
})
return newPromise
}
finally (callback) {
if (callback instanceof Function) {
// 调用then方法获取当前promise的状态
return this.then(value => { // 因为finally是链式调用, 所以需要返回一个promise对象,而then方法本身就会返回一个promise对象, 所以直接 return then
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
return MyPromise.resolve(callback()).then(() => {throw reason})
})
}
}
catch (failCallBack) {
return this.then(undefined, failCallBack) // 将成功回调置为undefined, 直接调用失败回调
}
static all (array) {// 接受一个数组作为参数
// all 方法返回的是一个promise对象, 那么必定要返回一个promise对象
let resultArr = [] //结果数组
let index = 0
return new MyPromise((resolve, reject) => {
// 循环array, 判断array中的每个值是普通值还是promise对象, 如果是普通值就直接放到结果数组当中, 如果是promise对象,
// 就先去执行promise对象, 然后再把promise对象的结果放到结果数组当中
function addData (key, value) {
resultArr[key] = value
index++
if (index = array.length) {// 因为会有array中可能会有异步代码, 所以判断index是否等于array的长度, 如果相等, 就证明array中的代码已经执行完毕,可以调用resolve方法
resolve(resultArr)
}
}
for (let i = 0; i < array.length; i++) {
let current = array[i]
if (current instanceof MyPromise) { //判断是否为promise对象, 如果不是, 那就是普通值
current.then(value => addData(i, value), reason => reject(reason))
} else {
addData(i, current)
}
}
})
}
static resolve (value) {
if (value instanceof MyPromise) return value // 判断是否为promise对象, 如果是则直接返回, 如果不是, 就要创建一个promise对象, 通过resolve返回value
return new MyPromise(resolve => resolve(value))
}
}
function resolvePromise (newPromise, c, resolve, reject) {
if (newPromise === c) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (c instanceof MyPromise) {
c.then(resolve, reject)
} else {
resolve(c)
}
}
到这一步, 手写promise已完成