Promise:简单实现promise

问题导向

手写promise,了解promise内部原理

如果你都有了答案,可以忽略本文章,或去JS学习地图寻找更多答案


代码如下

;(function (window) {
    const PENDING = 'pending'
    const RESOLVED = 'resolved'
    const REJECTED = 'rejected'

    function Promise(excutor) {
        let self = this
        self.status = PENDING
        self.data = undefined
        self.callbacks = []

        //立即同步执行excutor
        //当抛出异常时,执行失败处理回调
        try {
            excutor(resolve, reject)
        } catch (error) {
            reject(error)
        }

        function resolve(value) {
            //如果当前状态不是pending,不执行
            if (self.status !== PENDING) {
                return
            }
            console.log(this)
            //当执行resolve时,要做3件事:
            //1.将状态改为resolved
            self.status = RESOLVED
            //2.保存value数据
            self.data = value
            //3.如果有待执行callback,立即异步执行回调函数onResolved
            if (self.callbacks.length > 0) {
                //模拟微队列
                setTimeout(() => {
                    self.callbacks.forEach((callbacksObj) => {
                        callbacksObj.onResolved(value)
                    })
                })
            }
        }

        function reject(reason) {
            if (self.status !== PENDING) {
                return
            }

            console.log(this)
            self.status = REJECTED
            self.data = reason
            if (self.callbacks.length > 0) {
                setTimeout(() => {
                    self.callbacks.forEach((callbacksObj) => {
                        callbacksObj.onRejected(reason)
                    })
                })
            }
        }
    }

    //指定成功和失败的回调函数,返回一个新的promise对象
    Promise.prototype.then = function (onResolved, onRejected) {
        //指向回调的默认值(必须是函数)
        //向后传递成功的value
        onResolved =
            typeof onResolved === 'function' ? onResolved : (value) => value
        //实现异常穿透的代码
        onRejected =
            typeof onRejected === 'function'
                ? onRejected
                : (reason) => {
                      throw reason
                  }

        let self = this

        /*返回一个新的promise对象,而且新的promise对象可能会调用resolve或者reject,
        而调用哪个取决onResolved或者onRejected执行的结果*/
        return new Promise((resolve, reject) => {
            //调用指定的回调函数处理,根据执行的结果改变return的promise状态
            //因为内部要调用resolve/reject,只能定义在Promise内部
            function handle(callback) {
                //处理多种情况:
                //1.如果抛出异常
                //2.如果回调函数返回非promise
                //3.回调函数返回promise

                //为了捕获异常,使用try catch
                try {
                    //如果是成功回调,获取返回值,用于判断
                    const result = callback(self.data)
                    //3.返回非promise
                    if (result instanceof Promise) {
                        //难点:看不见的代码,原型链知识:
                        //因为返回了一个new Promise,所以每个实例都可以调用原型方法then
                        //只有then才能知道它返回的结果
                        // result.then(
                        //     (value) => resolve(value), //当result成功时,让新的promise也成功
                        //     (reason) => reject(reason) //当result失败时,让新的promise也失败
                        // )

                        //简洁版:
                        result.then(resolve, reject)
                        /*
                                如同:
                                function fn(){}
                                div.onclick = function(e){ fn(e) }
                                div.onclick = fn //两种等价,这个效率更高
                            */
                    } else {
                        resolve(result) //2.返回非promise
                    }
                } catch (error) {
                    reject(error) //1.如果抛出异常
                }
            }

            //如果是pending态,把回调存起来,以便调用
            if (self.status === PENDING) {
                self.callbacks.push({
                    //因为外面已经包了定时器了,所以这里不再需要了
                    //pending的状态(待调用),其实也要做同样的事情
                    onResolved() {
                        handle(onResolved)
                    },
                    onRejected() {
                        handle(onRejected)
                    },
                })
                //如果是resolved态,需要异步执行onResolved,并改变return的promise状态
            } else if (self.status === RESOLVED) {
                // 回调函数是异步的
                setTimeout(() => {
                    handle(onResolved)
                })
            } else {
                //如果是rejected态
                setTimeout(() => {
                    handle(onRejected)
                })
            }
        })
    }

    //指定失败的回调函数,返回一个promise对象
    Promise.prototype.catch = function (onRejected) {
        return this.then(undefined, onRejected)
    }

    //返回一个成功或失败的promise
    /*
    用法:
    const p1 = Promise.resolve('1')  如果是普通值,就走成功
    const p2 = Promise.resolve(Promise.resolve('2'))如果是成功promise
    const p3 = Promise.resolve(Promise.reject('3'))如果是失败promise
     */
    Promise.resolve = function (value) {
        return new Promise((resolve, reject) => {
            //value是promise
            if (value instanceof Promise) {
                value.then(resolve, reject)
            } else {
                //value不是promise
                resolve(value)
            }
        })
    }

    //返回一个指定reason必定是失败的promise
    Promise.reject = function (reason) {
        return new Promise((resolve, reject) => {
            reject(reason)
        })
    }

    //返回一个promise,所有promise都成功才成功
    //难点:怎么知道都成功了?
    //解决:计数与条件函数
    Promise.all = function (promiseArr) {
        // const result = new Array(promiseArr.length)
        const success = []
        const fail = []
        let resolvedCount = 0 //用于计算是否全部成功

        return new Promise((resolve, reject) => {
            promiseArr.forEach((p, index) => {
                // 包一层的写法:Promise.resolve(p).then(),如果数组中不是传promise,照样可以得到promise
                p.then(
                    (value) => {
                        resolvedCount++
                        success[index] = value

                        // if (resolvedCount === promiseArr.length) {
                        //     resolve(success)
                        // }
                    },
                    (reason) => {
                        fail[index] = reason
                        reject({ index: index, data: reason }) //rejected状态只会进入一次
                    }
                )
            })
            resolve({ success, fail })
        })
    }

    //返回一个promise,谁最快就返回谁,无论成功还是失败
    //难点:怎么知道谁最快?
    //解决:遍历 + 利用状态只会改变一次的特点
    Promise.race = function (promiseArr) {
        return new Promise((resolve, reject) => {
            //返回一个最快的值,需要遍历,才能知道谁最快
            promiseArr.forEach((p, index) => {
                p.then(
                    (value) => {
                        resolve(value)
                    },
                    (reason) => {
                        reject(reason)
                    }
                )
            })
        })
    }

    //只返回最快返回的成功的值
    Promise.race_success = function (promiseArr) {
        return new Promise((resolve, reject) => {
            promiseArr.forEach((p, index) => {
                p.then((value) => {
                    resolve(value)
                })
            })
        })
    }

    Promise.resolveDelay = function (value, await) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                if (value instanceof Promise) {
                    value.then(resolve, reject)
                } else {
                    resolve(value)
                }
            }, await)
        })
    }

    window.Promise = Promise
})(window)

学习更多

JS学习地图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值