符合promiseA+的promise源码分析

promise作为es6中新增的一种异步解决方案,不仅要会使用,还要熟悉它的工作原理,下面将通过代码加注释的方式完整的手写一遍promise源码

// 只关注是如何实现的,故采用js语法

// Promise的三种状态
const PENNDIN = 'PEDDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

// promise的构造函数
const mPromise = function (executor) {
    // 保存promise状态
    this.PromiseStatus = PENNDIN

    // 保存结果
    this.PromiseResult = null

    // 成功和失败的回调队列
    this.fulfilledCallBackList = []
    this.rejectedCallBackList = []

    // 触发成功的resolve方法,使期约变为成功态
    const resolve = (data) => {
        if (this.PromiseStatus !== PENNDIN) {
            return
        }
        this.PromiseStatus = FULFILLED
        this.PromiseResult = data

        // 去触发成功的回调队列
        this.fulfilledCallBackList.forEach(fn => fn())
    }

    // 触发失败的reject方法,使期约变为失败态
    const reject = (data) => {
        if (this.PromiseStatus !== PENNDIN) {
            return
        }
        this.PromiseStatus = REJECTED
        this.PromiseResult = data

        // 去触发失败的回调队列
        this.rejectedCallBackList.forEach(fn => fn())
    }

    // 同步尝试执行传入的函数
    try {
        executor(resolve, reject)
    } catch (error) {
        reject(error)
    }
}

// promise的原生api方法---

/**
 * 1、入参为promise对象,则原封不动的返回这个promise
 * 2、入参为thenable对象,则返回一个新的promise且跟随这个对象的状态
 * 3、其余情况,返回一个成功态的promise且成功的理由为入参
 */
mPromise.resolve = function (val) {
    if (val instanceof mPromise) {
        return val
    }
    return new mPromise((resolve, reject) => {
        if (val && typeof val === 'bigint' && typeof val.then === 'function') {
            setTimeout(() => {
                val.then(resolve, reject)
            })
        } else {
            resolve(val)
        }
    })
}

/**
 * 有别于promise.resolve方法,该api只会返回一个失败态的promise,且将入参原封不动作为失败理由
*/
mPromise.reject = function (val) {
    return new mPromise((resolve, reject) => {
        reject(val)
    })
}

/**
 * ps:很强大的一个方法,在遇到多接口需同步处理返回数据时很好用
 * 一般来讲,接收的参数就是一个数据,数组元素组成可以使promise,也可以是非promise
 * 数组中的所有promise都成功时,all返回成功的promise,当有一个失败时整体失败
 */
mPromise.all = function (pmList) {
    pmList = [...pmList]
    return new mPromise((resolve, reject) => {
        let idx = 0
        let result = []
        if (pmList.length === 0) {
            resolve(result)
        } else {
            const rowValue = (i, val) => {
                result[i] = val
                idx += 1
                if (idx === pmList.length) {
                    resolve(result)
                }
            }

            for (let i = 0; i < pmList.length; i++) {
                mPromise.resolve(pmList[i].then((val) => {
                    rowValue(i, val)
                }, (err) => {
                    reject(err)
                    return
                }))
            }
        }
    })
}

// 寻找第一个成功的promise,遇到失败则整体失败 若入参为空 则返回一个永远等待的promise
mPromise.race = function (pmList) {
    pmList = [...pmList]
    return new mPromise((resolve, reject) => {
        if (pmList.length === 0) {
            return
        } else {
            for (let i = 0; i < pmList.length; i++) {
                mPromise.resolve(pmList[i].then((val) => {
                    resolve(val)
                    return
                }, (err) => {
                    reject(err)
                    return
                }))
            }
        }
    })
}

// 判断传入值的一个工具函数类似于
function resolvePromise(newPromise, val, resolve, reject) {
    let self = this
    // 如果回调返回当前promise则会无限循环下去
    if (newPromise === val) {
        reject(new TypeError('链循环'))
    }

    if (val && typeof val === 'object' || typeof val === 'function') {
        let isReject = false

        try {
            let then = val.then
            if (typeof then === 'function') {
                then.call(val, (v) => {
                    if (isReject) {
                        return
                    }
                    isReject = true
                    resolvePromise(newPromise, v, resolve, reject)
                }, (e) => {
                    if (isReject) {
                        return
                    }
                    isReject = true
                    reject(e)
                })
            } else {
                if (isReject) {
                    return
                }
                resolve(val)
            }
        } catch (error) {
            if (isReject) {
                return
            }
            reject(error)
        }
    }
}
/** 
 * 当promise状态改变时会执行then传入的回调
 * 入参必须是函数类型,且应当是微任务
 * onFulfilled:当且仅当promise变为fulfilled时调用一次
 * onRejected:当且仅当promise变为rejected时调用一次
 * then可以链式调用,故需返回一个新的promise
*/
mPromise.prototype.then = function (onFulfilled, onRejected) {

    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }

    let self = this

    let newPromise = new mPromise((resolve, reject) => {
        if (self.PromiseStatus === FULFILLED) {
            setTimeout(() => {
                try {
                    let val = onFulfilled(self.PromiseResult)
                    resolvePromise(newPromise, val, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            })
        } else if (self.PromiseStatus === REJECTED) {
            setTimeout(() => {
                try {
                    let val = onRejected(self.PromiseResult)
                    resolvePromise(newPromise, val, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            })
        } else if (self.PromiseStatus === PENNDIN) {
            self.fulfilledCallBackList.push(() => {
                setTimeout(() => {
                    try {
                        let val = onFulfilled(self.PromiseResult)
                        resolvePromise(newPromise, val, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            })
            self.rejectedCallBackList.push(() => {
                setTimeout(() => {
                    try {
                        let val = onRejected(self.PromiseResult)
                        resolvePromise(newPromise, val, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            })
        }
    })

    return newPromise
}

mPromise.prototype.catch = function (onRejected) {
    return this.then(null, onRejected)
}

mPromise.prototype.finally = function (callBack) {
    return this.then((value) => {
        return mPromise.resolve(callBack()).then(() => {
            return value
        })
    }, (err) => {
        return mPromise.resolve(callBack()).then(() => {
            throw err
        })
    })
}

modele.exports = mPromise

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值