纯新手向,从零实现Promise (三)

50 阅读4分钟

Promise的静态方法实现起来就比较简单了

Promise.resolve()

static resolve = (value) => new Promise(res => res(value))

Promise.all()

 static all = (iPromises) => {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(iPromises)) {
            return reject(new TypeError('Argument must be an array'))
        }

        const results = [] // 用于存储每个 Promise 的结果
        let completedCount = 0 // 用于计数已经完成的 Promise 数量

        iPromises.forEach((promise, index) => {
            // 将 promise 转化为标准的 Promise 实例
            IPromise.resolve(promise)
                .then(value => {
                    results[index] = value; // 保存当前 Promise 的结果
                    completedCount++

                    // 如果所有的 Promise 都完成了,resolve 总结果
                    if (completedCount === iPromises.length) {
                        resolve(results)
                    }
                })
                .catch(reject) // 如果有任何一个 Promise 被拒绝,则立即 reject
        });

        // 如果传入的是空数组,直接 resolve 一个空数组
        if (iPromises.length === 0) {
            resolve([])
        }
    })
}

Promise.race()

static race = (iPromises) => {
    return new IPromise((resolve, reject) => {
        if (!Array.isArray(iPromises)) {
            return reject(new TypeError('Argument must be an array'))
        }

        if (iPromises.length === 0) return

        iPromises.forEach(iPromise => {
            // 确保每个输入都转化为标准 Promise
            IPromise.resolve(iPromise).then(resolve, reject)
        })
    });
}

前面漏实现catch了,补一个

catch = (err) => {
    return this.then(null, err)
}

Promise.allSettled()

static allSettled = (iPromises) => {
    return new IPromise(async (resolve) => {
        if (!Array.isArray(iPromises)) {
            return reject(new TypeError('Argument must be an array'))
        }

        // 如果传入的是空数组,直接 resolve 一个空数组
        if (iPromises.length === 0) {
            resolve([])
        }

        let completedCount = 0
        const allSettles = []

        const complete = (index, status, value) => {
            allSettles[index] = { status, value }
            completedCount++

            if (completedCount === iPromises.length) {
                resolve(allSettles)
            }
        };

        iPromises.forEach((iPromise, index) => {
            IPromise.resolve(iPromise).then(
                (value) => complete(index, 'fulfilled', value),
                (reason) => complete(index, 'rejected', reason)
            );
        });

    })
}

Promise.any()

 static any = (iPromises) => {
    return new IPromise((resolve, reject) => {
        if (!Array.isArray(iPromises)) {
            return reject(new TypeError('Argument must be an array'))
        }

        // 如果传入的是空数组,直接 reject 一个错误
        if (iPromises.length === 0) {
            return reject(new AggregateError('No Promise in array', []))
        }

        let rejectionCount = 0
        const errors = []

        iPromises.forEach((iPromise, index) => {
            IPromise.resolve(iPromise).then(
                (value) => resolve(value), // 一旦有一个 Promise 成功,直接 resolve
                (reason) => {
                    rejectionCount++
                    errors[index] = reason
                    if (rejectionCount === iPromises.length) {
                        reject(new AggregateError(errors, 'All promises were rejected'))
                    }
                }
            )
        })
    })
}

Promise.try()

static try = (fn) => {
    return new IPromise((resolve, reject) => {
        try {
            const result = fn()  // 调用传入的函数

            // 如果返回值是一个 Promise (即异步函数),我们需要处理其结果
            if (result && typeof result.then === 'function') {
                result.then(resolve, reject)  // 处理异步 Promise 错误
            } else {
                resolve(result)  // 如果是同步结果,直接 resolve
            }
        } catch (error) {
            reject(error)  // 捕获同步错误
        }
    })
}

Promise.withResolvers()

static withResolvers() {
    let resolve, reject;
    const promise = new IPromise((res, rej) => {
        resolve = res;
        reject = rej;
    });

    return {
        promise,
        resolve,
        reject
    };
}

全部代码

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class IPromise {

    constructor(excutor) {
        this.promiseState = PENDING // 三种状态:pending、fulfilled、rejected
        this.onResolveCallbacks = [] // 成功的回调
        this.onRejectCallbacks = [] // 失败的回调
        this.value = undefined
        this.reason = undefined

        try {
            excutor(this.resolve, this.reject) // 这里只能捕获同步错误
        } catch (error) {
            this.reject(error)
        }
    }

    resolve = (value) => {
        if (this.promiseState !== PENDING) return // 只处理Promise为pending的情况

        if (value === this) {
            // 避免返回自身导致死循环
            return this.reject(new TypeError("A promise cannot be resolved with itself."))
        }

        // 处理 value 为 Promise 的情况
        if (value instanceof IPromise) {
            return value.then(this.resolve, this.reject)
        }

        queueMicrotask(() => { // 需要放到微任务队列里面
            this.onResolveCallbacks.forEach(resolve => resolve(value))
        })

        this.promiseState = FULFILLED // 设置为成功的状态
        this.value = value // 保存一下结果
    }

    reject = (reason) => {
        if (this.promiseState !== PENDING) return
        this.promiseState = REJECTED // 设置为失败的状态
        this.reason = reason // 保存一下出错的原因

        queueMicrotask(() => { // 不放到微任务队列里的话,错误都捕获不到
            this.onRejectCallbacks.forEach(reject => reject(reason))
        })
    }

    then = (onFulfilled, onRejected) => {
        // 防止参数传空的情况
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }

        const handleCallback = (callback, value, resolve, reject) => {
            queueMicrotask(() => {
                try {
                    const result = callback(value)

                    if (result === this) {
                        // 避免循环引用
                        return reject(new TypeError("Cannot return the same promise from then()"))
                    }

                    if (result instanceof IPromise) {
                        // 如果返回值是 Promise,链接状态
                        result.then(resolve, reject)
                    } else {
                        resolve(result)
                    }
                } catch (error) {
                    reject(error)
                }
            })
        }

        return new IPromise((resolve, reject) => {

            if (this.promiseState === FULFILLED) {
                handleCallback(onFulfilled, this.value, resolve, reject)
            }

            if (this.promiseState === REJECTED) {
                handleCallback(onRejected, this.reason, resolve, reject)
            }

            if (this.promiseState === PENDING) {
                // 如果状态未被更改,说明是异步任务,推入对应的回调数组
                this.onResolveCallbacks.push(() => handleCallback(onFulfilled, this.value, resolve, reject))
                this.onRejectCallbacks.push(() => handleCallback(onRejected, this.reason, resolve, reject))
            }
        })

    }

    catch = (err) => {
        return this.then(null, err)
    }

    finally = (onFinally) => {
        return this.then(
            (value) =>
                P.resolve(onFinally()).then(() => value), // 继续传递成功的值
            (reason) =>
                P.resolve(onFinally()).then(() => {
                    throw reason; // 继续传递失败的原因
                })
        );
    }

    static resolve(value) { return new Promise(res => res(value)) }

    static all(iPromises) {
        return new Promise((resolve, reject) => {
            if (!Array.isArray(iPromises)) {
                return reject(new TypeError('Argument must be an array'))
            }

            // 如果传入的是空数组,直接 resolve 一个空数组
            if (iPromises.length === 0) {
                resolve([])
            }

            const results = [] // 用于存储每个 Promise 的结果
            let completedCount = 0 // 用于计数已经完成的 Promise 数量

            iPromises.forEach((promise, index) => {
                // 将 promise 转化为标准的 Promise 实例
                IPromise.resolve(promise)
                    .then(value => {
                        results[index] = value // 保存当前 Promise 的结果
                        completedCount++

                        // 如果所有的 Promise 都完成了,resolve 总结果
                        if (completedCount === iPromises.length) {
                            resolve(results)
                        }
                    })
                    .catch(reject) // 如果有任何一个 Promise 被拒绝,则立即 reject
            })

        })
    }

    static race(iPromises) {
        return new IPromise((resolve, reject) => {
            if (!Array.isArray(iPromises)) {
                return reject(new TypeError('Argument must be an array'))
            }

            if (iPromises.length === 0) return

            iPromises.forEach(iPromise => {
                // 确保每个输入都转化为标准 Promise
                IPromise.resolve(iPromise).then(resolve, reject)
            })
        })
    }

    static allSettled(iPromises) {
        return new IPromise(async (resolve) => {
            if (!Array.isArray(iPromises)) {
                return reject(new TypeError('Argument must be an array'))
            }

            // 如果传入的是空数组,直接 resolve 一个空数组
            if (iPromises.length === 0) {
                resolve([])
            }

            let completedCount = 0
            const allSettles = []

            const complete = (index, status, value) => {
                allSettles[index] = { status, value }
                completedCount++

                if (completedCount === iPromises.length) {
                    resolve(allSettles)
                }
            }

            iPromises.forEach((iPromise, index) => {
                IPromise.resolve(iPromise).then(
                    (value) => complete(index, 'fulfilled', value),
                    (reason) => complete(index, 'rejected', reason)
                )
            })

        })
    }

    static any(iPromises) {
        return new IPromise((resolve, reject) => {
            if (!Array.isArray(iPromises)) {
                return reject(new TypeError('Argument must be an array'))
            }

            // 如果传入的是空数组,直接 reject 一个错误
            if (iPromises.length === 0) {
                return reject(new AggregateError('No Promise in array', []))
            }

            let rejectionCount = 0
            const errors = []

            iPromises.forEach((iPromise, index) => {
                IPromise.resolve(iPromise).then(
                    (value) => resolve(value), // 一旦有一个 Promise 成功,直接 resolve
                    (reason) => {
                        rejectionCount++
                        errors[index] = reason
                        if (rejectionCount === iPromises.length) {
                            reject(new AggregateError(errors, 'All promises were rejected'))
                        }
                    }
                )
            })
        })
    }

    static try(fn) {
        return new IPromise((resolve, reject) => {
            try {
                const result = fn()  // 调用传入的函数

                // 如果返回值是一个 Promise (即异步函数),我们需要处理其结果
                if (result && typeof result.then === 'function') {
                    result.then(resolve, reject)  // 处理异步 Promise 错误
                } else {
                    resolve(result)  // 如果是同步结果,直接 resolve
                }
            } catch (error) {
                reject(error)  // 捕获同步错误
            }
        })
    }

    static withResolvers() {
        let resolve, reject;
        const promise = new IPromise((res, rej) => {
            resolve = res;
            reject = rej;
        });

        return {
            promise,
            resolve,
            reject
        };
    }
}