16.完整实现promise
Opened this issue · 0 comments
webVueBlog commented
// Promise/A+规范的三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
// 构造方法接受一个回调
constructor(promiseCallBack) {
this._resolveQueue = [] // then收集的执行成功的回调队列 .then可以调用多次
this._rejectQueue = [] // then收集的执行失败的回调队列
this._status = PENDING // Promise状态
this._value = undefined // 存储then回调return的值
// 由于 resolve / reject 是在promiseCallBack内部被调用
// 因此需要使用箭头函数固定this指向,否则找不到 this._resolveQueue
const _resolve = (val) => {
const run = () => {
// 状态只能由pending到fulfilled或rejected
if (this._status !== PENDING) return
this._status = FULFILLED
this._val = val
// then 方法可以被同一个 promise 调用多次
while (this._resolveQueue.length) {
// .then .reject 注册的回调只能被执行一次
const callback = this._resolveQueue.shift()
callback(val)
}
}
setTimeout(run) // 同步代码也要加上异步
}
// 实现同 resolve
const _reject = (val) => {
const run = () => {
// 状态只能由pending到fulfilled或rejected
if (this._status !== PENDING) return
this._status = REJECTED
while (this._rejectQueue.length) {
const callback = this._rejectQueue.shift()
callback(val)
}
}
setTimeout(run)
}
// new Promise()时立即执行 promiseCallBack, 并传入resolve和reject
promiseCallBack(_resolve, _reject)
}
// 这是链式调用原理
// 1. then返回一个新的promise
// 2. 执行then回调 获取返回值 这个返回值用于新的promise
// 3. 如果是Promise,那么等待Promise状态变更 传进 resolve,否则返回resolve
then(resolveFn, rejectFn) {
return new MyPromise((resolve, reject) => {
// 包装回调成函数
if (typeof resolveFn !== 'function') resolveFn = (value) = value
if (typeof rejectFn !== 'function') rejectFn = (error) = error
// 获取异步回调返回值 如果是Promise,那么等待Promise状态变更,否则直接resolve
const fulfilledFn = (value) => {
// 捕获执行错误
try {
// 执行异步 并获取返回值
const x = resolveFn(value)
// 如果是Promise,那么等待Promise状态变更,否则返回resolve
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (error) {
reject(error)
}
}
const rejectedFn = (error) => {
try {
const x= rejectFn(error)
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (error) {
reject(error)
}
}
// 根据状态执行操作
if (this._status === PENDING) {
// 等待执行
this._resolveQueue.push(fulfilledFn)
this._rejectQueue.push(rejectedFn)
} else if (this._status === FULFILLED) {
// 直接执行then回调
fulfilledFn(this._value) // this._value是constructor期间执行的值
} else if (this._status === REJECTED) {
// 直接执行catch回调
rejectedFn(this._value)
}
})
}
// 静态的resolve方法 用于快速声明一个promise
static resolve(value) {
if (value instanceof MyPromise) return value // 根据规范,如果参数是Promise实例,直接return这个实例
return new MyPromise((resolve) => resolve(value)) // 立即执行
}
// 静态的reject方法
static reject (reason) {
// 将promise改为reject
return new MyPromise((resolve, reject) => reject(reason))
}
// 异步失败回调 在异步后面链接一个错误的回调 失败了即执行错误回调
catch(rejectFn) {
return this.then(undefined, rejectFn)
}
// 将回调传入 .then 和 catch 的resolveFn中 状态改变后 执行回调
finally(callback) {
return this.then(
(value) => MyPromise.resolve(callback()).then(() => value),
(reason) => MyPromise.resolve(callback()).then(() => { throw reason })
)
}
// 全部完成才是完成 一个失败即失败
// promise.all
all(promiseArr) {
return new MyPromise((resolve, reject) => {
const resArr = []
let count = 0
for (const [index, element] of promiseArr.entries()) {
// Promise.resolve(element) 用于处理传入值不为 Promise 的情况
MyPromise.resolve(element)
.then((res) => {
count++
resArr[index] = res
if (count === promiseArr.length) {
resolve(resArr)
}
})
.catch((err) => {
reject(err)
})
}
})
}
// 竞争promise 一个出现状态即为最终状态
race(promiseArr) {
return new MyPromise((resolve, reject) => {
for (const element of promiseArr.values()) {
MyPromise.resolve(element)
.then((res) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
}
}
}
// 数组内部都是异步任务,返回所有异步任务的结果 无论是否成功
allSettled(promisesArr) {
// 重写每一个promise 将结果返回到数组元素中 使其都能成功
return new MyPromise((resolve) => {
const results = []
promisesArr.forEach(promise => {
promise.then(res => {
results.push({ status: FULFILLED, value: res })
if (results.length === promisesArr.length) {
resolve(results)
}
}, err => {
results.push({ status: REJECTED, value: err })
if (results.length === promises.length) {
resolve(results)
}
})
})
})
}
}
// 使用方法
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 500)
})
p1.then((res) => {
console.log('p1', res)
return 2
})
.then((res) => {
console.log('3', res)
return 3
})
.then((res) => {
console.log('4', res)
})