ES6 Promise实现

ES6使用Typescript实现Promise

const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

type Executor = (resolve?: (data: unknown) => void, reject?: (reason: unknown) => void) => any
type OnRejected = (error?: any) => any
type OnFulfilled = (data?: any) => any
type Resolve = (data?: unknown) => any
type Reject = (data?: unknown) => any

class MyPromise {
    #state: string
    #result: unknown
    #handlers: any[]

    constructor(executor: Executor) {
        this.#state = PENDING
        this.#handlers = []
        const resolve: Resolve = (data: unknown) => {
            this.#changeState(FULFILLED, data);
        }
        const reject: Reject = (reason: unknown) => {
            this.#changeState(REJECTED, reason)
        }
        try {
            executor(resolve, reject)
        } catch (err) {
            reject(err)
        }
    }

    #changeState(state: string, reason: unknown) {
        if (this.#state !== PENDING) return
        this.#state = state
        this.#result = reason
        this.#run()
    }

    #isPromiseLike(value: any) {
        if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
            return typeof value.then === 'function'
        }
        return false
    }

    #runMicoTask(func: MutationCallback) {
        if (typeof process === 'object' && typeof process.nextTick === 'function') {
            process.nextTick(func)
        } else if (typeof MutationObserver === 'function') {
            const ob = new MutationObserver(func)
            const textNode = document.createTextNode('1')
            ob.observe(textNode, {
                characterData: true
            })
            textNode.data = '2'
        } else {
            setTimeout(func, 0);
        }
    }

    #runOne(callback: any, resolve: any, reject: any) {
        queueMicrotask(() => {
            if (typeof callback !== 'function') {
                const settled = this.#state === FULFILLED ? resolve : reject
                settled(this.#result)
                return
            }
            try {
                const data = callback(this.#result)
                if (this.#isPromiseLike(data)) {
                    data.then(resolve, reject)
                } else {
                    resolve(data)
                }
            } catch (error) {
                reject(error)
            }
        })
    }

    #run() {
        if (this.#state === PENDING) return
        while (this.#handlers.length) {
            const { onFulfilled, onRejected, resolve, reject } = this.#handlers.shift()
            if (this.#state === FULFILLED) {
                this.#runOne(onFulfilled, resolve, reject)
            } else {
                this.#runOne(onRejected, resolve, reject)
            }
        }
    }

    then(onFulfilled?: OnFulfilled, onRejected?: OnRejected) {
        return new MyPromise((resolve, reject) => {
            this.#handlers.push({
                onFulfilled,
                onRejected,
                resolve,
                reject
            })
            this.#run()
        })
    }

    catch(onRejected: OnRejected) {
        return this.then(undefined, onRejected)
    }

    finally(onFinlly: Function) {
        return this.then(data => {
            onFinlly()
            return data
        }, err => {
            onFinlly()
            throw err
        })
    }

    static resolve(value: any) {
        if (value instanceof MyPromise) return value
        let _resolve: Resolve, _reject: Reject
        const p = new MyPromise((resolve, reject) => {
            _reject = reject
            _resolve = resolve
        })
        if (p.#isPromiseLike(value)) {
            value.then(_resolve, _reject)
        } else {
            _resolve(value)
        }
        return p
    }

    static reject(reason: any) {
        return new MyPromise((resolve, reject) => {
            reject(reason)
        })
    }

    static all(promises: any[]) {
        return new MyPromise((resolve, reject) => {
            let results = [];
            let counter = 0;

            // 为数组中的每个promise添加回调
            promises.forEach((promise, index) => {
                Promise.resolve(promise).then(result => {
                    results[index] = result;
                    // 当所有promise都解决时,解决自定义的Promise
                    if (++counter === promises.length) {
                        resolve(results);
                    }
                }).catch(reject); // 如果任何promise失败,则立即停止并失败
            });
        });
    }

    static any(promises: any[]) {
        if (!Array.isArray(promises)) {
            throw new TypeError('Promises must be an array');
        }

        return new MyPromise((resolve, reject) => {
            let resolved = false;
            const errors: any[] = [];

            promises.forEach((promise) => {
                if (resolved) return;

                Promise.resolve(promise)
                    .then(resolve)
                    .catch((error) => {
                        errors.push(error);
                        if (errors.length === promises.length) {
                            reject(errors);
                        }
                    });
            });
        });
    }

    static rice(promises: any[]) {
        if (!Array.isArray(promises)) {
            throw new TypeError('promises must be an array');
        }

        return new MyPromise((resolve, reject) => {
            let resolved = false;
            const errors: any[] = [];

            promises.forEach((promise) => {
                if (resolved) return;

                Promise.resolve(promise)
                    .then(resolve)
                    .catch((error) => {
                        reject(errors);
                    });
            });
        });
    }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值