This article: Implement the PromiseA+ specification and Promise (prototype, static, extra extension, etc.) method by hand, yes, come on

Handwritten promises (conforming to PromiseA + spec)

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) {
        typeofresolveFn ! = ='function' && (resolveFn = value= > value)
        typeofrejectFn ! = ='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)
    }
}
Copy the code

1, implement promise.prototype. Catch

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

2, realize the Promise. Prototype. Finally

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

3, implement promise.resolve

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

4, Implement promise.reject

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

5, implement 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)
        })
    })
}
Copy the code

6. Implement promise.race

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

7, implement 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)
            })
        })
    })
}
Copy the code

Promise.retry: Specifies the number of retries. Otherwise, the request will fail

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()
    })
}
Copy the code

9, implement promise.series: serial execution of all return Promise requests (similar to AsyncSeriesHook in Tabable)

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)) }) }Copy the code

MaxRun: Specifies the maximum number of concurrent requests a Promise can make. If all requests are successful, all results will be returned. If a request fails, the failure result will be returned

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()
    })
}
Copy the code