Promise(A+规范)以及Promise相关API全部实现(JS)

346 阅读1分钟

本文: 手写实现PromiseA+规范以及Promise(原型,静态,额外扩展等)方法,没错,来吧~~~

手写Promise(符合PromiseA + 规范)

const FULFILLED = 'fulfilled', REJECTED = 'rejected', PENDING = 'pending'
class Promise_ {
    constructor(excutor) {
        this.status = PENDING
        this.value = undefined
        this.reason = undefined
        this.resolveList = []
        this.rejectList = []
        const resolve = value => {
            if (this.status === PENDING) {
                this.status = FULFILLED
                this.value = value
                this.resolveList.forEach(fn => fn(value))
            }
        }
        const reject = reason => {
            if (this.status === PENDING) {
                this.status = REJECTED
                this.reason = reason
                this.rejectList.forEach(fn => fn(reason))
            }
        }
        try {
            excutor(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }
    then(resolveFn, rejectFn) {
        typeof resolveFn !== 'function' && (resolveFn = value => value)
        typeof rejectFn !== 'function' && (rejectFn = reason => { throw reason })
        let bridgePromise
        return bridgePromise = new Promise_((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        const x = resolveFn(this.value)
                        resolvePromise(x, bridgePromise, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                });
            }
            if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        const x = rejectFn(this.reason)
                        resolvePromise(x, bridgePromise, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                });
            }
            if (this.status === PENDING) {
                this.resolveList.push(value => {
                    setTimeout(() => {
                        try {
                            const x = resolveFn(value)
                            resolvePromise(x, bridgePromise, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    });
                })
                this.rejectList.push(reason => {
                    setTimeout(() => {
                        try {
                            const x = rejectFn(reason)
                            resolvePromise(x, bridgePromise, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    });
                })
            }
        })
    }
}
function resolvePromise(x, bridgePromise, resolve, reject) {
    if (x === bridgePromise) return reject(new TypeError('circle'))
    if (x !== null && (typeof x === 'function' || typeof x === 'object')) {
        let called = false
        try {
            const then = x.then
            if (typeof then === 'function') {
                then.call(x,
                    y => {
                        if (called) return
                        called = true
                        resolvePromise(y, bridgePromise, resolve, reject)
                    },
                    error => {
                        if (called) return
                        called = true
                        reject(error)
                    }
                )
            } else {
                resolve(x)
            }
        } catch (error) {
            if (called) return
            called = true
            reject(error)
        }
    } else {
        resolve(x)
    }
}

1,实现Promise.prototype.catch

Promise_.prototype.catch = function (callback) {
    return this.then(null, callback)
}

2,实现Promise.prototype.finally

Promise_.prototype.finally = function (callback) {
    return this.then(
        v => Promise_.resolve(callback()).then(() => v),
        err => Promise_.resolve(callback()).then(() => { throw err })
    )
}

3,实现Promise.resolve

Promise_.resolve = function (val) {
    return new Promise_(resolve => resolve(val))
}

4,实现Promise.reject

Promise_.reject = function (err) {
    return new Promise_((resolve, reject) => reject(err))
}

5,实现Promise.all

Promise_.all = function (list) {
    let res = [], count = 0
    return new Promise_((resolve, reject) => {
        list.forEach((p, i) => {
            p.then(v => {
                res[i] = v; ++count >= list.length && resolve(res)
            }).catch(reject)
        })
    })
}

6,实现Promise.race

 Promise_.race = function (list) {
        return new Promise_((resolve, reject) => list.forEach(p => p.then(resolve).catch(reject)))
    }

7,实现Promise.allSettled

Promise_.allSettled = function (list) {
    let res = [], count = 0
    return new Promise_(resolve => {
        list.forEach((p, i) => {
            p.then(v => {
                res[i] = { status: 'fulfilled', value: v }; ++count >= list.length && resolve(res)
            }).catch(err => {
                res[i] = { status: 'rejected', reason: err }; ++count >= list.length && resolve(res)
            })
        })
    })
}

8,实现Promise.retry:指定请求重试次数,重试次数内完成则完成,否则失败

Promise_.retry = function (request, count) {
    let rejectCount = 0
    return new Promise_((resolve, reject) => {
        function step() {
            request().then(resolve).catch(err => ++rejectCount < count ? step() : reject(err))
        }
        step()
    })
}

9,实现Promise.series:串行执行所有返回Promise请求(类似tabable中AsyncSeriesHook)

Promise_.series = function (list, ...args) {
    let i = 0
    return new Promise_((resolve, reject) => {
        function step(fn) {
            fn().then(v => ++i < list.length ? step(list[i].bind(null, v)) : resolve(v)).catch(reject)
        }
        step(list[i].bind(null, ...args))
    })
}

10,实现Promise.maxRun:指定Promise请求最大并发数量,所有成功,则返回所有请求结果,如果某请求失败,则返回该失败结果

Promise_.maxRun = function (list, max) {
    let i = 0, maxCount = 0, res = [], count = 0;
    return new Promise_((resolve, reject) => {
        function step() {
            for (; i < list.length && maxCount < max; i++ , maxCount++) {
                const idx = i
                list[idx]().then(
                    v => {
                        res[idx] = v; count++; maxCount--;
                        if (count >= list.length) resolve(res)
                        else maxCount < max && step()
                    }
                ).catch(reject)
            }
        }
        step()
    })
}