一、剖析Promise的实现过程
1、Promise 是一个类,在执行这个类的时候,需要传递一个执行器进去,执行器会立即执行
2、Promise 中有三种状态,分别是fulfilled 成功 rejected 失败 pending 等待
- pending -> fulfilled 成功
- pending -> rejected 失败
3、resolve 和 reject 是用来更改状态的; 设置对象的结果的
- resolve: fulfilled
- reject: rejected
4、then 方法内部做的的事情就是判断状态 如果调用的状态是成功 调用成功的回调函数 如果状是失败 调用失败的回调
5、then 成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因
6、当resolve 和 reject 是异步更改状态的时候,执行方法时状态为pending,并状态将如何改变,因此需要将成功、失败的回调函数存储在实例属性中
7、resolve 和 reject 清楚异步操作何时回调,因此可以在 resolve 和 reject 中执行成功、失败的回调函数
8、当多次调用 MyPromise 实例的 then 方法时,如果是resolve 和 reject 是同步更改状态没问题,但如果是异步更改状态,就需要依次存储多个成功、失败的回调函数
9、then方法是可以被链式调用,要实现链式调用,then需要返回一个新的MyPromise,同时需要将上一个then方法中回调函数的返回值,传递给下一个then方法中的回调函数
10、then方法返回的值,可能是普通值,也可能是一个MyPromise,当为MyPromise时需要调用它的then方法,根据不同的状态执行resolve, reject,将value, reason传给下一个then方法
11、当then方法中返回的值为一个MyPromise,并且这个MyPromise就是该then方法的返回值时,会发生MyPromise的循环调用,这种情况在执行中会报错的。
12、这里要处理两个异常,一个是构造函数中执行器的代码执行异常 另一个是then方法回调中的异常
13、处理then方法中不同的状态下兼容异步操作
14、then 方法的参数是可选的,当传递一个参数或者什么都不传,该怎样处理呢?
15、promise 对象上有一个静态方法all,用于批量执行promise ,并接收返回的结果数组,若其中一个失败,则调用失败回调函数,只有全部执行成功,才调用成功回调函数。
二、代码实现
// 2、Promise 中有三种状态,分别是fulfilled 成功 rejected 失败 pending 等待
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 1.1、Promise是一个类
class MyPromise {
// 1.2、在执行类的时候需要传入一个执行器,执行器会立即执行
constructor(exexcutor) {
// 12.1、处理两个异常之一:构造函数中执行器的代码执行异常
try {
// 3.1、resolve 和 reject 的作用是更改对象的状态; 设置对象的结果
exexcutor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING
value = undefined
reason = undefined
// 13.2、如果是异步更改状态,就需要依次存储多个成功、失败的回调函数(同步也兼容)
successCallFn = []
failureCallFn = []
// 7.1、resolve 和 reject 清楚异步操作何时回调,因此可以在 resolve 和 reject 中执行成功、失败的回调函数
resolve = (value) => {
// 3.2、由于pending -> fulfilled 成功 pending -> rejected 失败
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// 13.4、异步操作完成后,依次调用之前储存的回调函数
while (this.successCallFn.length) this.successCallFn.shift()()
}
reject = (reason) => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
while (this.failureCallFn.length) this.failureCallFn.shift()()
}
// 13.1、处理then方法中不同的状态下兼容异步操作
then (successCallFn, failureCallFn) {
// 14、then 方法的参数是可选的,当传递一个参数或者什么都不传,该怎样处理呢?
successCallFn = successCallFn ? successCallFn : value => value
failureCallFn = failureCallFn ? failureCallFn : reason => { throw reason }
// 9.1、then方法是可以被链式调用,要实现链式调用,then需要返回一个新的MyPromise
let promise2 = new MyPromise((resolve, reject) => {
// 4.1、then 方法内部做的的事情就是判断状态
// 4.2、如果调用的状态是FULFILLED,调用成功回调函数 如果状态是REJECTED,调用失败回调函数
if (this.status === FULFILLED) {
// 13.3、 异步执行获取promise2实例
setTimeout(() => {
// 12.1、处理两个异常之二:then方法回调中的异常
try {
// 5.1、成功回调有一个参数是this.value,它是resolve设置的对象结果
// 10.1、then方法返回的值,可能是普通值,也可能是一个MyPromise,封装一个函数paserPomiseX处理
let x = successCallFn(this.value)
paserPomiseX(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
// 5.2、失败回调有一个参数是this.reason,它是reject设置的原因结果
let x = failureCallFn(this.reason)
paserPomiseX(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === PENDING) { // 当前状态为pending,状态该如何改变?
this.successCallFn.push(() => {
// 6.1、当resolve 和 reject 是异步更改状态的时候,执行方法时状态为pending
setTimeout(() => {
try {
let x = successCallFn(this.value)
paserPomiseX(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
this.failureCallFn.push(() => {
setTimeout(() => {
try {
let x = failureCallFn(this.reason)
paserPomiseX(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
// 17、不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
finally (callfn) {
// 17.1、通过this.then拿到实例对象的状态
return this.then(value => {
return MyPromise.resolve(callfn()).then(() => value)
}, reason => {
return MyPromise.resolve(callfn()).then(() => { throw reason })
})
}
// 18、用于指定发生错误时的回调函数,Promise对象具有’冒泡‘性质,会一直向后传递,直到被捕获为止。即错误总会被下一个catch语句捕获。
catch (failureCallFn) {
return this.then(undefined, failureCallFn)
}
// 15、promise 对象上有一个静态方法all,用于批量执行promise ,并接收返回的结果数组,若其中一个失败,则调用失败回调函数,只有全部执行成功,才调用成功回调函数。
static all (array) {
let index = 0
let result = []
// 15.2、Mypromise.all 返回结果是一个Mypromise对象
return new MyPromise((resolve, reject) => {
// 15.3、定义一个变更结果数组的函数
function addData (key, value) {
result[key] = value
index++
// 15.4、判断数组中promise对象都执行结束
if (index === array.length) {
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
const current = array[i]
// 15.1、判断数组中单个元素是否为MyPromise
if (current instanceof MyPromise) {
current.then(value => addData(i, value), reason => reject(reason))
} else {
// 普通值
addData(i, array[i])
}
}
})
}
// 16、Promise对象上有一个静态方法resolve,用于将现有对象转换为Promise对象,从而控制异步流程。
static resolve (value) {
if (value instanceof MyPromise) return value
return new MyPromise(resolve => resolve(value))
}
}
function paserPomiseX (promise2, x, resolve, reject) {
// 11.1、当then方法中返回的值为一个MyPromise,并且这个MyPromise就是该then方法的返回值时,会发生MyPromise的循环调用,这种情况在执行中会报错的。
if (promise2 === x) {
reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
return
}
if (x instanceof MyPromise) {
// 10.2、当为MyPromise时需要调用它的then方法,根据不同的状态执行resolve, reject,将value, reason传给下一个then方法
x.then(resolve, reject)
} else {
// 10.3、then方法返回的值是普通值
resolve(x)
}
}