参考: https://juejin.cn/post/7047492676190634021#comment
https://juejin.cn/post/7102708871763853348
1、前置知识:
(1)promise的基本知识
- 作用:异步处理;解决“回调地狱”,提高可读性
- 三种状态:pending、resolved(也叫fulfilled)、rejected(后两种状态只能从pending转换过来,不存在resolved、rejected互转)
实例方法:
- then:会返回一个promise对象;参数是两个回调函数,resolved、rejected状态对应的执行函数
- catch:相当于then中的第二个函数
- all:一个promise对象数组,全部执行成功则返回一个状态为resolved的promise对象;否则rejected
- race:一个promise对象数组,返回第一个完成的promise对象,无论是resolved还是rejected
(2)原型
在MyPromise类的原型上写方法,实例p可以继承
2、Promise实现
(1)构造函数
function MyPromise(executor) {
this.status = 'pending'
this.result = null
// 箭头函数不会改变this指向,this仍然指向当前的promise对象,而不是指向resolve函数
const resolve = (data) => {
if(this.status !== 'pending')
return
this.status = 'resolved'
this.result = data
// 队列思想,先进先出;
// 1、执行then方法时,为pending状态的每个promise对象保存一对回调函数;
// 2、等到状态变为resolved时,从队列中取出暂存的回调函数,顺序调用
while(this.onResolvedCallbacks.length > 0) {
this.onResolvedCallbacks.shift()() // 调用
this.onRejectedCallbacks.shift()
}
}
const reject = (data) => {
if(this.status !== 'pending')
return
this.status = 'rejected'
this.result = data
while(this.onRejectedCallbacks.length > 0) {
this.onResolvedCallbacks.shift()
this.onRejectedCallbacks.shift()() // 调用
}
}
// 把写好的resolve、reject作为MyPromise构造函数的两个参数
executor(resolve, reject)
}
关于executor(resolve, reject)的理解:
① 先看promise对象的创建形式:
// 箭头函数就对应了上面代码中的executor
let p1 = new MyPromise((resolve, rejct)=>{
// 函数体
// 需要显式调用resolve、reject函数,修改promise状态
resolve('ok')
})
② resolve、reject
这两个函数,是我们在MyPromise中事先写好的,使用executor(resolve, reject),分配给MyPromise构造函数的两个对应参数
改成以下形式也是一样的效果,因为这里是形参:
let p1 = new MyPromise((success, failed)=>{
success(‘ok’)
})
然后,在函数体中调用时,才会执行相应的函数代码
③ executor的作用
将实例的参数名(回调函数名)跟MyPromise类中的resolve、reject对应起来
(2)then、catch方法
① then返回的是一个promise对象(支持链式调用)
MyPromise.prototype.then = function (onResolved, onRejected) {
// 如果传入参数不是函数,为其初始化为空函数
onResolved = typeof onResolved === 'function' ? onResolved : ()=>{
}
onRejected = typeof onRejected === 'function' ? onRejected : ()=>{
}
return new MyPromise((resolve, reject) => {
// this指向执行then方法的MyPromise实例
if(this.status === 'resolved') {
let res = onResolved(this.result) // then方法的返回值
resolve(res) // 传递给下一个then
}
if(this.status === 'rejected' && onRejected) {
let err = onRejected(this.result)
reject(err)
}
// 说明前一步还没有完成,先保存两个回调,等待完成后再执行
if(this.status === 'pending') {
this.onResolvedCallbacks.push(()=>{
let res = onResolved(this.result)
resolve(res)
})
this.onRejectedCallbacks.push(()=>{
let err = onRejected(this.result)
reject(err)
})
}
})
}
② catch相当于第二个参数为空函数的then方法
MyPromise.prototype.catch = function(onRejected) {
if(this.status === 'rejected') {
onRejected(this.result)
}
if(this.status === 'pending') {
this.onResolvedCallbacks.push(()=>{
// push一个空的回调函数,占位
})
this.onRejectedCallbacks.push(()=>{
onRejected(this.result)
})
}
}
③ 链式调用then方法:
let p1 = new MyPromise((resolve, reject)=>{
// resolve('ok')
reject('error')
})
p1.then((value)=>{
console.log('value', value)
return value
}
,(reason)=>{
console.log('reason:', reason) // 执行,输出 reason:error
return reason
}).then((res)=>{
console.log('res:', res)
},(err)=>{
console.log('err:', err) // 执行,输出 err:error
return 'catch_Error'
}).catch((err)=>{
console.log('catch:', err) // 执行,输出 catch:catch_Error
})
(3)all、race方法
① all:一个promise对象数组,只有当所有对象的状态都为resolved时,返回一个resolved的promise对象(由原数组的返回值组成);否则返回第一个rejected的promise对象的值
MyPromise.prototype.all = function(promiseArray) {
const values = []
let count = 0
return new MyPromise((resolve, reject)=>{
promiseArray.forEach((p, index) => {
// 把p包装成MyPromise对象,因为可能传入的p并不是promise对象
p = p instanceof MyPromise ? p : new MyPromise((resolve, reject) => resolve(p))
p.then(
(value)=>{
count++
values[index] = value // 保持跟原数组顺序一致
if(count === promiseArray.length) {
resolve(values)
console.log('status:', this.status)
}
},
(err) => {
reject(err)
}
)
})
})
}
② race:一个promise对象数组,返回第一个执行完成的promise对象,无论成功与否
MyPromise.prototype.race = function(promiseArray) {
return new MyPromise((resolve, reject)=>{
promiseArray.forEach((p) => {
p = p instanceof MyPromise ? p : new MyPromise((resolve, reject) => {
resolve(p) })
p.then(
(value)=>{
resolve(value)
},
(err) => {
reject(err)
}
)
})
})
}
调用all、race方法:
let p1 = new MyPromise((resolve, reject)=>{
resolve('p1')
})
let p2 = new MyPromise((resolve, reject)=>{
resolve('p2')
})
let p3 = new MyPromise((resolve, reject)=>{
resolve('p3')
})
let p4 = new MyPromise((resolve, reject)=>{
reject('p4')
})
let P1 = new MyPromise((resolve, reject)=>{
})
P1.all([p1,p2,p3]).then((res)=>{
console.log('res:', res)
}, (err)=>{
console.log('err:', err)
})
P1.all([p1,p2,p4]).then((res)=>{
console.log('res:', res)
}, (err)=>{
console.log('err:', err)
})
P1.all(['1','2','3']).then((res)=>{
console.log('res:', res)
}, (err)=>{
console.log('err:', err)
})
P1.race([p1,p2,p4]).then((res)=>{
console.log('res:', res)
}, (err)=>{
console.log('err:', err)
})
P1.race([p4,p1,p2]).then((res)=>{
console.log('res:', res)
}, (err)=>{
console.log('err:', err)
})
3、补充
catch方法、then方法中第二个函数的区别?
——catch相当于then的第二个方法,但是指下一个then,不是前一个then
——在同一个then中,第二个方法捕获不到第一个方法抛出的异常
let p = new Promise((resolve, reject)=>{
})
p.then(()=>{
}, ()=>{
})
.catch(()=>{
})
p.then(()=>{
},()=>{
})
.then(()=>{
}, ()=>{
// 相当于这个方法
})