一、目录
-
定义CYPromise构造函数及基本状态
-
resolve和reject方法
-
then方法
-
catch方法
-
finally方法
-
CYPromise.resolve和CYPromise.reject静态方法
-
CYPromise.all和CYPromise.allSettled静态方法
-
实现Promise.race和Promise.any静态方法
二、实现过程
第1步:定义CYPromise构造函数,并实现基本的状态属性
首先,我们需要创建一个名为CYPromise的类,并定义三种状态:pending、fulfilled和rejected。CYPromise类的构造函数将接收一个执行器(executor)函数作为参数。执行器函数会立即执行,并接收两个参数:resolve和reject,它们分别用于将Promise状态从pending更改为fulfilled或rejected。
我们还需要在类中实现状态的改变以及状态改变时对应的值(value)或原因(reason)的存储。
下面是CYPromise类的基本结构以及构造函数的实现:
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class CYPromise {
constructor(executor) {
// 初始化状态为pending
this.status = PROMISE_STATUS_PENDING
// 初始化成功的值为undefined
this.value = undefined
// 初始化失败的原因为undefined
this.reason = undefined
// 定义resolve方法
const resolve = (value) => {
// 只有在pending状态才能更改状态和值
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
}
}
// 定义reject方法
const reject = (reason) => {
// 只有在pending状态才能更改状态和原因
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
}
}
//执行回调函数
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
}
在这一步中,我们定义了CYPromise类的基本结构,并实现了构造函数以及状态属性的初始化。我们还定义了resolve和reject方法,并在执行器函数中使用它们。如果执行器函数抛出异常,我们会捕获它并将Promise状态更改为rejected。
第2步:实现resolve和reject两个核心方法
接下来,我们需要在CYPromise类中实现两个核心方法:resolve和reject。这两个方法用于处理异步操作的结果。我们会将这两个方法从构造函数中提取出来,并作为类的实例方法。同时,我们需要处理异步操作的结果,将成功或失败的处理函数存储在队列中,在resolve或reject方法中逐个执行这些处理函数。
下面是CYPromise类的实现:
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class CYPromise {
constructor(executor) {
// 初始化状态为pending
this.status = PROMISE_STATUS_PENDING
// 初始化成功的值为undefined
this.value = undefined
// 初始化失败的原因为undefined
this.reason = undefined
//保存fulfilled时的回调函数
this.onFulfilledFns = []
//保存rejected时的回调函数
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务使其在then方法之后调用
queueMicrotask(() => {
// 若当前状态不是pending时,结束(当resolve在前面,是为了取消执行reject中的微任务)
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
// 遍历数组,执行每个回调函数
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
});
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务使其在then方法之后调用
queueMicrotask(() => {
// 若当前状态不是pending时,结束(当reject在前面,是为了取消执行resolve中的微任务)
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
// 遍历数组,执行每个回调函数
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
//执行回调函数
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
// 1.如果在then调用的时候, 状态已经确定下来,就直接执行传进来的函数(延迟调用)
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
onFulfilled(this.value)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
onRejected(this.reason)
}
// 2.将成功回调和失败的回调放到数组中(多次调用promise.then时)
if (this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(onFulfilled)
this.onRejectedFns.push(onRejected)
}
}
}
在这一步中,我们实现了resolve和reject方法。当Promise状态从pending变为fulfilled或rejected时,我们将执行相应的处理函数队列中的函数。此外,我们还对构造函数中的异常处理进行了优化。
第3步:实现then方法
接下来,我们需要在CYPromise类中实现then方法,在第2步的基础上进行优化。then方法用于为Promise实例注册成功和失败的处理函数。它返回一个新的Promise实例,以便我们可以链式调用。
我们需要实现一个名为execFunctionWithCatchError的工具函数。这个函数用于处理then方法返回的新Promise实例以及它们对成功和失败函数的处理。
首先,我们实现execFunctionWithCatchError工具函数:
// 工具函数
// execFn: 要执行的函数
// value: 传入的值
// resolve: 成功时调用的函数
// reject:失败时调用的函数
function execFunctionWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
resolve(result)
} catch (err) {
reject(err)
}
}
接下来,我们在CYPromise类中实现then方法:
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
// 工具函数
// execFn: 要执行的函数
// value: 传入的值
// resolve: 成功时调用的函数
// reject:失败时调用的函数
function execFunctionWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
resolve(result)
} catch (err) {
reject(err)
}
}
class CYPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
//保存fulfilled时的回调函数
this.onFulfilledFns = []
//保存rejected时的回调函数
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务使其在then方法之后调用
queueMicrotask(() => {
// 若当前状态不是pending时,结束(当resolve在前面,是为了取消执行reject中的微任务)
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
// 遍历数组,执行每个回调函数
this.onFulfilledFns.forEach(fn => {
fn()//此处没有参数
})
});
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务使其在then方法之后调用
queueMicrotask(() => {
// 若当前状态不是pending时,结束(当reject在前面,是为了取消执行resolve中的微任务)
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
// 遍历数组,执行每个回调函数
this.onRejectedFns.forEach(fn => {
fn()//此处没有参数
})
})
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
return new CYPromise((resolve, reject) => {
// 1.如果在then调用的时候, 状态已经确定下来
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
// try {
// const value = onFulfilled(this.value)
// resolve(value)
// } catch(err) {
// reject(err)
// }
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
// try {
// const reason = onRejected(this.reason)
// resolve(reason)
// } catch(err) {
// reject(err)
// }
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
}
// 2.将成功回调和失败的回调放到数组中
if (this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(() => {
// try {
// const value = onFulfilled(this.value)
// resolve(value)
// } catch(err) {
// reject(err)
// }
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
})
this.onRejectedFns.push(() => {
// try {
// const reason = onRejected(this.reason)
// resolve(reason)
// } catch(err) {
// reject(err)
// }
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
})
}
})
}
}
第4步:实现catch方法
catch方法它等价于调用then方法时仅传入一个失败处理函数。此时要考虑到,上一个promise对象的then函数并没有传入onReject函数,而是把错误抛出去给下一个promise对象(即当前catch调用then函数返回的promise对象)处理,所以在then方法中对未传入onReject函数进行优化,给一个默认的函数,并在函数中抛出异常,才能把错误信息传递给下一个promise对象。
下面是CYPromise类的catch方法实现,并对then方法进行优化:
class CYPromise {
// ...其他代码
// then方法
then(onFulfilled, onRejected) {
// 若then中没有err处理时,抛出错误进入catch中进行处理;若then中有错误处理,则自己进行错误处理
//主要解决调用then时,没有处理失败函数,而是让catch去处理失败函数时的情况
const defaultOnRejected = err => {
throw err
}
onRejected = onRejected || defaultOnRejected
return new CYPromise((resolve, reject) => {
// 1.如果在then调用的时候, 状态已经确定下来
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
}
// 2.将成功回调和失败的回调放到数组中
if (this.status === PROMISE_STATUS_PENDING) {
if (onFulfilled) this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
})
if (onRejected) this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
})
}
})
}
catch (onRejected) {
return this.then(undefined, onRejected)
}
}
在这一步中,我们实现了catch方法。它只接受一个参数:onRejected,这个参数是失败的处理函数。我们通过调用then方法并传入undefined作为成功处理函数来实现这个方法。
第5步:实现finally方法
finally方法它等价于调用then方法时,不论成功或失败时,都将调用传入的函数。
另外要注意一点,若在finally之前调用了catch函数,此时要考虑到在catch函数中调用then函数时,onFulfilled参数是undefined的情况,所以在then方法中也要对成功函数为undefined时进行梳理,此时直接把成功值返回即可。
下面是CYPromise类的catch方法实现,并对then方法进行优化:
class CYPromise {
// ...其他代码
then(onFulfilled, onRejected) {
// 若then中没有err处理时,抛出错误进入catch中进行处理;若then中有错误处理,则自己进行错误处理
//主要解决调用then时,没有处理失败函数,而是让catch去处理失败函数时的情况
const defaultOnRejected = err => {
throw err
}
onRejected = onRejected || defaultOnRejected
// 若then中没有onFulfilled函数时,将value返回,进入下一个promise.then中
// 主要解决catch函数中,调用then方法时,onFulfilled为undefined时的情况
const defaultOnFulfilled = value => {
return value
}
onFulfilled = onFulfilled || defaultOnFulfilled
return new CYPromise((resolve, reject) => {
// 1.如果在then调用的时候, 状态已经确定下来
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
}
// 2.将成功回调和失败的回调放到数组中
if (this.status === PROMISE_STATUS_PENDING) {
if (onFulfilled) this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
})
if (onRejected) this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
})
}
})
}
catch (onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
}
在这一步中,我们实现了finally方法。它接受一个参数:onFinally,这个参数是一个处理函数。无论Promise实例成功还是失败,这个处理函数都会被调用。我们通过调用then方法并传入两个相同的处理函数来实现这个方法。这两个处理函数分别用于成功和失败的情况,它们都会返回一个新的Promise实例,以确保onFinally是异步执行的。
第6步:实现Promise.resolve和Promise.reject静态方法
接下来,我们需要在CYPromise类中实现两个静态方法:resolve和reject。这两个方法可以快速地创建一个已经解决或拒绝的Promise实例。
下面是CYPromise类的resolve和reject静态方法实现:
class CYPromise {
// ...其他代码
// 静态方法(类方法)
static resolve(value) {
return new CYPromise((resolve) => resolve(value))
}
// 静态方法(类方法)
static reject(reason) {
return new CYPromise((resolve, reject) => reject(reason))
}
}
在这一步中,我们实现了resolve和reject静态方法。resolve方法接受一个参数:value,用于创建一个已经解决的Promise实例。reject方法接受一个参数:reason,用于创建一个已经拒绝的Promise实例。
第7步:实现Promise.all和Promise.allSettled静态方法
最后,我们需要在CYPromise类中实现两个静态方法:all和allSettled。all方法用于将多个Promise实例包装成一个新的Promise实例,只有当所有的Promise实例都成功时,新的Promise实例才会成功;allSettled方法用于将多个Promise实例包装成一个新的Promise实例,只要所有的Promise实例都完成(成功或失败),新的Promise实例就会成功。
下面是CYPromise类的all和allSettled静态方法实现:
class CYPromise {
// ...其他代码
static all(promises) {
// 问题关键: 什么时候要执行resolve, 什么时候要执行reject
return new CYPromise((resolve, reject) => {
const values = []
promises.forEach(promise => {
promise.then(res => {
values.push(res)
if (values.length === promises.length) {
resolve(values)
}
}, err => {
reject(err)
})
})
})
}
static allSettled(promises) {
return new CYPromise((resolve) => {
const results = []
promises.forEach(promise => {
promise.then(res => {
results.push({ status: PROMISE_STATUS_FULFILLED, value: res})
if (results.length === promises.length) {
resolve(results)
}
}, err => {
results.push({ status: PROMISE_STATUS_REJECTED, value: err})
if (results.length === promises.length) {
resolve(results)
}
})
})
})
}
}
在这一步中,我们实现了all和race静态方法。all方法接受一个数组参数,该数组包含多个Promise实例。我们遍历这个数组,使用CYPromise.resolve将每个实例包装成一个标准的Promise实例。当所有实例都解决时,我们将结果数组传递给新的Promise实例的resolve方法。race方法的实现类似,我们遍历输入数组,当任何一个实例解决或拒绝时,立即调用新的Promise实例的resolve或reject方法。
第8步:实现Promise.race和Promise.any静态方法
接下来,我们需要在CYPromise类中实现两个额外的静态方法:race和any。race方法则是将多个Promise实例包装成一个新的Promise实例,只要其中一个Promise实例成功或失败,新的Promise实例就会立即成功或失败;any方法则是将多个Promise实例包装成一个新的Promise实例,只要其中一个Promise实例成功,新的Promise实例就会立即成功。如果所有实例都失败,新的Promise实例将失败。
下面是CYPromise类的allSettled和any静态方法实现:
class CYPromise {
// ...其他代码
static race(promises) {
return new CYPromise((resolve, reject) => {
promises.forEach(promise => {
// promise.then(res => {
// resolve(res)
// }, err => {
// reject(err)
// })
promise.then(resolve, reject)
})
})
}
static any(promises) {
// resolve必须等到有一个成功的结果
// reject所有的都失败才执行reject
const reasons = []
return new CYPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(res => {
resolve(res)
}, err => {
reasons.push(err)
if (reasons.length === promises.length) {
reject(new AggregateError(reasons))
}
})
})
})
}
}
在这一步中,我们实现了allSettled和any静态方法。allSettled方法接受一个数组参数,该数组包含多个Promise实例。我们遍历这个数组,使用CYPromise.resolve将每个实例包装成一个标准的Promise实例。当所有实例都完成(成功或失败)时,我们将结果数组传递给新的Promise实例的resolve方法。any方法的实现类似,我们遍历输入数组,当任何一个实例解决时,立即调用新的Promise实例的resolve方法。当所有实例都拒绝时,我们将错误数组传递给新的Promise实例的reject方法。
276

被折叠的 条评论
为什么被折叠?



