Custom Promise - Javascript

  • Custom Promise
        const STATE = {
            FULFILLED: "fulfilled",
            REJECTED: "rejected",
            PENDING: "pending",
        }
    
        class MyPromise {
            #thenCbs = []
            #catchCbs = []
            #state = STATE.PENDING
            #value
            #onSuccessBind = this.#onSuccess.bind(this)
            #onFailBind = this.#onFail.bind(this)
    
            constructor(cb) {
            try {
                cb(this.#onSuccessBind, this.#onFailBind)
            } catch (e) {
                this.#onFail(e)
            }
            }
    
            #runCallbacks() {
            if (this.#state === STATE.FULFILLED) {
                this.#thenCbs.forEach(callback => {
                callback(this.#value)
                })
    
                this.#thenCbs = []
            }
    
            if (this.#state === STATE.REJECTED) {
                this.#catchCbs.forEach(callback => {
                callback(this.#value)
                })
    
                this.#catchCbs = []
            }
            }
    
            #onSuccess(value) {
            queueMicrotask(() => {
                if (this.#state !== STATE.PENDING) return
    
                if (value instanceof MyPromise) {
                value.then(this.#onSuccessBind, this.#onFailBind)
                return
                }
    
                this.#value = value
                this.#state = STATE.FULFILLED
                this.#runCallbacks()
            })
            }
    
            #onFail(value) {
            queueMicrotask(() => {
                if (this.#state !== STATE.PENDING) return
    
                if (value instanceof MyPromise) {
                value.then(this.#onSuccessBind, this.#onFailBind)
                return
                }
    
                if (this.#catchCbs.length === 0) {
                throw new UncaughtPromiseError(value)
                }
    
                this.#value = value
                this.#state = STATE.REJECTED
                this.#runCallbacks()
            })
            }
    
            then(thenCb, catchCb) {
            return new MyPromise((resolve, reject) => {
                this.#thenCbs.push(result => {
                if (thenCb == null) {
                    resolve(result)
                    return
                }
    
                try {
                    resolve(thenCb(result))
                } catch (error) {
                    reject(error)
                }
                })
    
                this.#catchCbs.push(result => {
                if (catchCb == null) {
                    reject(result)
                    return
                }
    
                try {
                    resolve(catchCb(result))
                } catch (error) {
                    reject(error)
                }
                })
    
                this.#runCallbacks()
            })
            }
    
            catch(cb) {
            return this.then(undefined, cb)
            }
    
            finally(cb) {
            return this.then(
                result => {
                cb()
                return result
                },
                result => {
                cb()
                throw result
                }
            )
            }
    
            static resolve(value) {
            return new Promise(resolve => {
                resolve(value)
            })
            }
    
            static reject(value) {
            return new Promise((resolve, reject) => {
                reject(value)
            })
            }
    
            // Promise.all(p1, p2, p3).then([v1, v2, v3]).catch(e)
            static all(promises) {
            const results = []
            let completedPromises = 0
    
            return new MyPromise((resolve, reject) => {
                for (let i = 0; i < promises.length; i++) {
                const promise = promises[i]
                promise
                    .then(value => {
                    completedPromises++
                    results[i] = value
                    if (completedPromises === promises.length) {
                        resolve(results)
                    }
                    })
                    .catch(reject)
                }
            })
            }
    
            static allSettled(promises) {
            const results = []
            let completedPromises = 0
    
            return new MyPromise(resolve => {
                for (let i = 0; i < promises.length; i++) {
                const promise = promises[i]
                promise
                    .then(value => {
                    results[i] = { status: STATE.FULFILLED, value }
                    })
                    .catch(reason => {
                    results[i] = { status: STATE.REJECTED, reason }
                    })
                    .finally(() => {
                    completedPromises++
                    if (completedPromises === promises.length) {
                        resolve(results)
                    }
                    })
                }
            })
            }
    
            static race(promises) {
            return new MyPromise((resolve, reject) => {
                promises.forEach(promise => {
                promise.then(resolve).catch(reject)
                })
            })
            }
    
            static any(promises) {
            const errors = []
            let rejectedPromises = 0
    
            return new MyPromise((resolve, reject) => {
                for (let i = 0; i < promises.length; i++) {
                const promise = promises[i]
                promise.then(resolve).catch(value => {
                    rejectedPromises++
                    errors[i] = value
                    if (rejectedPromises === promises.length) {
                    reject(new AggregateError(errors, "All promises were rejected"))
                    }
                })
                }
            })
            }
        }
    
        class UncaughtPromiseError extends Error {
            constructor(error) {
            super(error)
            this.stack = `(in promise) ${error.stack}`
            }
        }
    
        module.exports = MyPromise
    
  • var.then is executed if promise is resolve & .catch is executed when promise is reject
        var.then(function() {statement})
        .catch (function() {statement})
    
Share: