一、Promise的基本结构搭建
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
const resolve = () => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
console.log('resolve执行了')
}
}
const reject = () => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
console.log('reject执行了')
}
}
executor(resolve, reject)
}
}
const promise = new MyPromise((resolve, reject) => {
console.log('executor执行了')
resolve()
reject()
})
Promise会有三种状态(pending,fulfilled,rejected).
当成功时,resolve会被回调,并且状态会被改变(pending -> fulfilled);当失败时,reject函数会被回调,并且状态会被改变(pending -> rejected).
Promise的状态一旦被确定,就不可更改了,那我们通过status来统一管理状态
二、Promise对象方法then方法的搭建
1.Promise状态确定后,then回调的执行问题
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
const resolve = () => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
console.log('resolve执行了')
// 开始执行then传入的第一个回调函数了
this.onFulfilled()
}
}
const reject = () => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
console.log('reject执行了')
// 开始执行then传入的第二个回调函数了
this.onRejected()
}
}
executor(resolve, reject)
}
then(onFulfilled, onRejected) {
this.onFulfilled = onFulfilled
this.onRejected = onRejected
}
}
const promise = new MyPromise((resolve, reject) => {
console.log('executor执行了')
resolve()
reject()
})
promise.then(() => {
console.log('我是成功时被回调的')
}, () => {
console.log('我是失败时被回调的')
})
then方法接收两个参数,第一个是执行resolve被立即调用了,第二个是执行reject被立即调用执行了.
因此我们需要存储一下这两个参数,在执行resolve/reject调用相应的回调函数.
我们执行一下,看看??? 额,报错了 => TypeError: this.onFulfilled is not a function. 哦,原来是代码执行的顺序问题,当执行resolve/reject函数时,this.onFulfilled()/this.onRejected()还不知道在哪里定义的嘞(此时我们还没有执行then方法呢)..... 额,怎么办呢,有了,事件循环
2.代码执行顺序问题
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
// 开始执行then传入的第一个回调函数了
queueMicrotask(() => {
this.onFulfilled(this.value)
})
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
// 开始执行then传入的第二个回调函数了
queueMicrotask(() => {
this.onRejected(this.reason)
})
}
}
executor(resolve, reject)
}
then(onFulfilled, onRejected) {
this.onFulfilled = onFulfilled
this.onRejected = onRejected
}
}
const promise = new MyPromise((resolve, reject) => {
console.log('executor执行了')
resolve('成功111')
reject('失败111')
})
promise.then((res) => {
console.log('我是成功时被回调的:', res)
}, (err) => {
console.log('我是失败时被回调的:', err)
})
我们使用queueMicrotask再试试. ok,问题解决了,嘿嘿. 我们知道then的两个回调函数也是可以接收参数的,那我们就再调用这两个函数的参数里面进行添加就可以了. yes,成功了,那我们多次调用试试看会不会有什么问题
3.then多次调用的问题
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
// 开始执行then传入的第一个回调函数了
queueMicrotask(() => {
// this.onFulfilled(this.value)
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
// 开始执行then传入的第二个回调函数了
queueMicrotask(() => {
// this.onRejected(this.reason)
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
executor(resolve, reject)
}
then(onFulfilled, onRejected) {
// this.onFulfilled = onFulfilled
// this.onRejected = onRejected
this.onFulfilledFns.push(onFulfilled)
this.onRejectedFns.push(onRejected)
}
}
const promise = new MyPromise((resolve, reject) => {
console.log('executor执行了')
resolve('成功111')
reject('失败111')
})
promise.then((res) => {
console.log('res1:', res)
}, (err) => {
console.log('err1:', err)
})
promise.then((res) => {
console.log('res2:', res)
}, (err) => {
console.log('err2:', err)
})
我们发现,只有最后一个then方法中的回调函数被执行了,前面的却没有被执行.这是为什么嘞???
我们看then方法,this.xxx = xxx ...哦,执行then的时候,被覆盖掉了.那我们通过数组,将then方法的所有回调分别都存储起来,然后在执行resolve/reject函数里面,统一执行这些存储的函数. 说干就干...... OK,可以. 那我们在不同时间段里面调用then会怎么样呢?
4.Promise状态改变后,再次调用then的问题
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
// 开始执行then传入的第一个回调函数了
queueMicrotask(() => {
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
// 开始执行then传入的第二个回调函数了
queueMicrotask(() => {
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
executor(resolve, reject)
}
then(onFulfilled, onRejected) {
// this.onFulfilledFns.push(onFulfilled)
// this.onRejectedFns.push(onRejected)
// console.log('this.onFulfilledFns', this.onFulfilledFns)
// 状态已被确定
if(this.status === PROMISE_STATUS_FULFILLED) {
onFulfilled(this.value)
}
if(this.status === PROMISE_STATUS_REJECTED) {
onRejected(this.reason)
}
// 状态未确定
if(this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(onFulfilled)
this.onRejectedFns.push(onRejected)
}
}
}
const promise = new MyPromise((resolve, reject) => {
resolve('成功111')
reject('失败111')
})
promise.then((res) => {
console.log('res1:', res)
}, (err) => {
console.log('err1:', err)
})
promise.then((res) => {
console.log('res2:', res)
}, (err) => {
console.log('err2:', err)
})
setTimeout(() => {
promise.then((res) => {
console.log('res3:', res)
}, (err) => {
console.log('err3:', err)
})
}, 300)
我们发现setTimeout里面的then并没有被回调,这又是为什么嘞???
setTimeout是宏任务,queueMicrotask是微任务.所有微任务执行完后,才会执行宏任务.
我们在then方法里面打印,then的两个回调函数是被添加到数组里面了,只不过它是在300ms后添加进去的.然而,等它添加进去,Promise的状态早已被改变了,自然then的两个回调都不会执行了... 没事,总会有办法解决的,还记得我们的三种状态吗?当状态已经被确定的时候,成功和失败的结果我们都能拿到,我们执行并把结果传进去调用就可以啦.
5.then的链式调用问题
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
// 开始执行then传入的第一个回调函数了
queueMicrotask(() => {
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
// 开始执行then传入的第二个回调函数了
queueMicrotask(() => {
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
try {
executor(resolve, reject)
} catch(err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
// // 状态已被确定
// if(this.status === PROMISE_STATUS_FULFILLED) {
// onFulfilled(this.value)
// }
// if(this.status === PROMISE_STATUS_REJECTED) {
// onRejected(this.reason)
// }
// // 状态未确定
// if(this.status === PROMISE_STATUS_PENDING) {
// this.onFulfilledFns.push(onFulfilled)
// this.onRejectedFns.push(onRejected)
// }
return new MyPromise((resolve, reject) => {
// 状态已被确定
if(this.status === PROMISE_STATUS_FULFILLED) {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch(err) {
reject(err)
}
}
if(this.status === PROMISE_STATUS_REJECTED) {
try {
const reason = onRejected(this.reason)
resolve(reason)
} catch(err) {
reject(err)
}
}
// 状态未确定
if(this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(() => {
try {
const value = onFulfilled(this.value)
resolve(value)
} catch(err) {
reject(err)
}
})
this.onRejectedFns.push(() => {
try {
const reason = onRejected(this.reason)
resolve(reason)
} catch(err) {
reject(err)
}
})
}
})
}
}
const promise = new MyPromise((resolve, reject) => {
// resolve('成功111')
reject('失败111')
})
promise.then((res) => {
console.log('res1:', res)
return 'abc'
}, (err) => {
console.log('err1:', err)
return 345
}).then((res) => {
console.log('res2:', res)
}, (err) => {
console.log('err2:', err)
})
then的链式调用,归根结底就是then的回调函数会返回一个新的Promise
新的Promse的结果,会作为下一个then回调的参数
看到这,大概心里也有一个底了.我们先在then方法里面返回一个新的Promise吧.
我们如何拿到上一个Promise的结果呢,这不是简单嘛.onFulfilled(this.value) / onRejected(this.reason) 不是现成的吗. 但是this.onFulfilledFns.push(onFulfilled) / this.onRejectedFns.push(onRejected)怎么办呢? 直接看骚操作
既然返回的是一个新的Promise,又需要拿到上一次Promise的结果,我们直接将代码放一块,何乐而不为呢.
三、Promise对象方法catch方法的搭建
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
function handleError(fn, value, resolve, reject) {
try {
const v = fn(value)
resolve(v)
} catch(err) {
reject(err)
}
}
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
// 开始执行then传入的第一个回调函数了
queueMicrotask(() => {
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
// 开始执行then传入的第二个回调函数了
queueMicrotask(() => {
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
try {
executor(resolve, reject)
} catch(err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
onRejected = onRejected || (err => { throw err })
return new MyPromise((resolve, reject) => {
// 状态已被确定
if(this.status === PROMISE_STATUS_FULFILLED) {
handleError(onFulfilled, this.value, resolve, reject)
}
if(this.status === PROMISE_STATUS_REJECTED) {
handleError(onRejected, this.reason, resolve, reject)
}
// 状态未确定
if(this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(() => {
handleError(onFulfilled, this.value, resolve, reject)
})
this.onRejectedFns.push(() => {
onRejected(onRejected, this.reason, resolve, reject)
})
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
}
const promise = new MyPromise((resolve, reject) => {
// resolve('成功111')
reject('失败111')
})
promise.then((res) => {
// console.log('res1:', res)
return 'abc'
// throw new Error()
}).then(res => {
console.log('res2:', res)
throw new Error()
}).catch(err => {
console.log('err1:', err)
return 'aaa'
}).then(res => {
console.log('res3:', res)
}).catch(err => {
console.log('err2:', err)
})
catch会依次捕捉每个Promise的错误,也就是说如果第一个Promise错误了,就会执行catch中的代码.如果第二个Promise错误了,也会执行catch中的代码.那我们如何让第一个Promise出错,并且让catch捕获到呢? 嗯,想到了.抛出一个错误
四、Promise对象方法finally方法的搭建
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
function handleError(fn, value, resolve, reject) {
try {
const v = fn(value)
resolve(v)
} catch(err) {
reject(err)
}
}
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
// 开始执行then传入的第一个回调函数了
queueMicrotask(() => {
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
// 开始执行then传入的第二个回调函数了
queueMicrotask(() => {
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
try {
executor(resolve, reject)
} catch(err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
onRejected = onRejected || (err => { throw err })
return new MyPromise((resolve, reject) => {
// 状态已被确定
if(this.status === PROMISE_STATUS_FULFILLED) {
handleError(onFulfilled, this.value, resolve, reject)
}
if(this.status === PROMISE_STATUS_REJECTED) {
handleError(onRejected, this.reason, resolve, reject)
}
// 状态未确定
if(this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(() => {
handleError(onFulfilled, this.value, resolve, reject)
})
this.onRejectedFns.push(() => {
handleError(onRejected, this.reason, resolve, reject)
})
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
}
const promise = new MyPromise((resolve, reject) => {
// resolve('成功111')
reject('失败111')
})
promise.then(res => {
console.log('res:', res)
}).catch(err => {
console.log('err:', err)
}).finally(() => {
console.log('finally被执行了')
})
finally方法是在Promise状态确定了之后,都会执行的,并且是在then和catch之后执行的,我们直接将finally内的回调写入then方法的两个回调函数里面多好啊.我们来试试,可行不
五、Promise类方法resolve/reject的搭建
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
function handleError(fn, value, resolve, reject) {
try {
const v = fn(value)
resolve(v)
} catch(err) {
reject(err)
}
}
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
// 开始执行then传入的第一个回调函数了
queueMicrotask(() => {
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
// 开始执行then传入的第二个回调函数了
queueMicrotask(() => {
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
try {
executor(resolve, reject)
} catch(err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
onRejected = onRejected || (err => { throw err })
return new MyPromise((resolve, reject) => {
// 状态已被确定
if(this.status === PROMISE_STATUS_FULFILLED) {
handleError(onFulfilled, this.value, resolve, reject)
}
if(this.status === PROMISE_STATUS_REJECTED) {
handleError(onRejected, this.reason, resolve, reject)
}
// 状态未确定
if(this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(() => {
handleError(onFulfilled, this.value, resolve, reject)
})
this.onRejectedFns.push(() => {
handleError(onRejected, this.reason, resolve, reject)
})
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new MyPromise((resolve, reject) => resolve(value))
}
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
}
MyPromise.resolve('哈哈哈').then(res => { console.log('res:', res) })
MyPromise.reject('嘿嘿嘿').catch(err => { console.log('err:', err) })
Promise的类方法resolve/reject本质就是调用Promise,将结果resolve/reject出去.
六、Promise类方法all/allSettled/race/any的搭建
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
function handleError(fn, value, resolve, reject) {
try {
const v = fn(value)
resolve(v)
} catch(err) {
reject(err)
}
}
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
// 开始执行then传入的第一个回调函数了
queueMicrotask(() => {
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if(this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
// 开始执行then传入的第二个回调函数了
queueMicrotask(() => {
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
try {
executor(resolve, reject)
} catch(err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
onRejected = onRejected || (err => { throw err })
return new MyPromise((resolve, reject) => {
// 状态已被确定
if(this.status === PROMISE_STATUS_FULFILLED) {
handleError(onFulfilled, this.value, resolve, reject)
}
if(this.status === PROMISE_STATUS_REJECTED) {
handleError(onRejected, this.reason, resolve, reject)
}
// 状态未确定
if(this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(() => {
handleError(onFulfilled, this.value, resolve, reject)
})
this.onRejectedFns.push(() => {
handleError(onRejected, this.reason, resolve, reject)
})
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new MyPromise((resolve, reject) => resolve(value))
}
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
static all(promises) {
return new MyPromise((resolve, reject) => {
const result = []
promises.forEach(promise => {
promise.then(res => {
result.push(res)
if(result.length === promises.length) {
resolve(result)
}
}, err => {
reject(err)
})
})
})
}
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
const result = []
promises.forEach(promise => {
promise.then(res => {
result.push(res)
if(result.length === promises.length) {
resolve(result)
}
}, err => {
result.push(err)
if(result.length === promises.length) {
resolve(result)
}
})
})
})
}
static race(promises) {
return new MyPromise((resolve, reject) => {
const result = []
promises.forEach(promise => {
promise.then(res => {
resolve(res)
}, err => {
reject(err)
})
})
})
}
static any(promises) {
return new MyPromise((resolve, reject) => {
const result = []
promises.forEach(promise => {
promise.then(res => {
resolve(res)
}, err => {
result.push(err)
if(result.length === promises.length) {
reject(new AggregateError(result))
}
})
})
})
}
}
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('resolve111')
reject('reject111')
}, 1000)
})
const p2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('resolve222')
reject('reject222')
}, 1000)
})
const p3 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('resolve333')
reject('reject333')
}, 1000)
})
MyPromise.all([p1, p2, p3]).then(res => {
console.log('res:', res)
}).catch(err => {
console.log('err:', err)
})