剖析 手写Promise 代码

为了加深手写 promise 代码的理解,会记录各个情况下promise代码执行顺序,和为什么要这么写。
首先贴上完整的手写Promise代码:(尚硅谷课程代码)

class Promise {
    // 构造方法
    constructor(executor) {
        this.status = 'preding' // 给promise对象指定status属性,初始值为prending
        this.data = undefined //给promise对象指定一个用于存储结果数据的属性
        const self = this // 保存实例对象的this的值
        this.callbacks = []// 每一个元素的结构:{onResolved(){},onRejected() {}}
        // Promise实例对象的resolve
        // 返回一个指定成功的promise
        function resolve(value) {
            // 如果当前状态不是Prending,直接结束
            if (self.status != 'preding') {
                return
            }
            //改变状态
            self.status = 'resolved'
            //保存异步操作得到的value数据
            self.data = value
            // 执行onResolve回调函数
            setTimeout(() => {
                self.callbacks.forEach(item => {
                    item.onResolved(value)
                })
            })
        }
        // Promise实例对象的reject(定义在Promise的原型上面)
        // 返回一个指定失败的promise
        function reject(reason) {
            // 如果当前状态不是Prending,直接结束
            if (self.status != 'preding') {
                return
            }
            //改变状态
            self.status = 'rejected'
            //保存value数据
            self.data = reason
            // 执行onRejected回调函数
            setTimeout(() => {
                self.callbacks.forEach(item => {

                    item.onRejected(reason)
                })
            })
        }

        // 执行回调函数
        try {
            // 同步调用 [执行器函数]
            executor(resolve, reject)
        } catch (error) {
            // 修改promise对象状态为失败
            return reject(error)
        }
    }
    // then方法封装
    then(onResolved, onRejected) {
        const self = this
        // 判断回调函数参数
        if (typeof onRejected != 'function') {
            onRejected = reason => {
                throw reason;
            }
        } // 考虑异常穿透,没有指定reject,初始化reject为异常
        if (typeof onResolved != 'function') {
            onResolved = value => value
        } // 默认省略resolve,reject回调,初始化resolve,then也可以继续往下传
        return new Promise((resolve, reject) => {
            // 封装函数
            function callBack(onFun) {
                try {
                    // 获取回调函数执行结果 
                    let result = onFun(self.data)
                    //判断 结果是否是Promise对象
                    if (result instanceof Promise) {
                        result.then(v => {
                            resolve(v)
                        }, r => {
                            reject(r)
                        })
                    } else {//不是直接成功
                        //状态为成功
                        resolve(result)
                    }
                } catch (error) {
                    reject(error)
                }
            }
            // 调用回调函数 
            if (this.status === 'resolved') {
                setTimeout(() => {
                    callBack(onResolved)
                })
            }
            if (this.status === 'rejected') {
                setTimeout(() => {
                    callBack(onRejected)
                })
            }
            // 改变状态前,绑定回调函数
            if (this.status === 'preding') {
                // 保存回调函数
                this.callbacks.push({
                    onResolved: () => callBack(onResolved),
                    onRejected: () => callBack(onRejected)
                })
            }
        })
    }

在各个场景下手写Promise的执行顺序:

同步任务下,then方法返回promise对象

      let p = new Promise((resolve, reject) => {
            resolve('ok')

        });
        const result = p.then(value => {
            //1.返回字符串
            // return `hello promise`
            // 2.返回promise
            // return new Promise((resolve, reject) => {
            //     resolve("success")
            // })
            // 3.抛出异常
            throw '123'
        }, reason => {
            console.log(reason)
        })
        console.log(result)

在内置的promise下:
在这里插入图片描述
在手写的promise下:
在这里插入图片描述
分析:
两者是正确的,由于then方法的回调函数是异步执行的,所以console.log(result)会在先打印出来,所以promise会显示为preding,但当所以同步事件执行完后,会执行异步操作,所以
value => {throw ‘123’} 会执行,使得result的状态变成了rejected。
代码分析:
对构造函数来说,

   let p = new Promise((resolve, reject) => {
            resolve('ok')

        });

首先会对promise进行初始化包括:状态、结果数据、以及then绑定回调函数容器(callbacks)
初始化完成后,会调用执行函数,对执行函数中绑定的回调(resolve,reject)进行调用。
从而修改promise对象的状态(状态只能改变一次)和绑定值(这里的’ok’) 可能执行then方法的回调,这里没有then,就不执行;最后这句就返回 resolved状态,data为’ok’的promise对象。

  constructor(executor) {
        this.status = 'preding' // 给promise对象指定status属性,初始值为prending
        this.data = undefined //给promise对象指定一个用于存储结果数据的属性
        const self = this // 保存实例对象的this的值
        this.callbacks = []// 每一个元素的结构:{onResolved(){},onRejected() {}}
        // Promise实例对象的resolve
        // 返回一个指定成功的promise
        function resolve(value) {
            // 如果当前状态不是Prending,直接结束
            if (self.status != 'preding') {
                return
            }
            //改变状态
            self.status = 'resolved'
            //保存异步操作得到的value数据
            self.data = value
            // 执行onResolve回调函数
            setTimeout(() => {
                self.callbacks.forEach(item => {
                    item.onResolved(value)
                })
            })
        }
        // Promise实例对象的reject(定义在Promise的原型上面)
        // 返回一个指定失败的promise
        function reject(reason) {
            // 如果当前状态不是Prending,直接结束
            if (self.status != 'preding') {
                return
            }
            //改变状态
            self.status = 'rejected'
            //保存value数据
            self.data = reason
            // 执行onRejected回调函数
            setTimeout(() => {
                self.callbacks.forEach(item => {

                    item.onRejected(reason)
                })
            })
        }

        // 执行回调函数
        try {
            // 同步调用 [执行器函数]
            executor(resolve, reject)
        } catch (error) {
            // 修改promise对象状态为失败
            return reject(error)
        }
    }

下面这段代码: 调用then方法,(then方法总是返回一个promise对象,这是支持链式调用的原因)then 方法是整个promise的核心部分。then方法返回的promise对象状态由then方法里面回调函数执行结果决定,这里throw ’123‘, 所以 result的状态肯定是reject。

1.由于then方法可以省略写成功回调和失败的回调,所以需要在不传回调函数时,给它们默认值。
2.然后是返回新的promise对象,同样是调用构造函数,初始化状态为(predding),然后执行构造函数中的executor(执行器函数)调用回调函数,这里的回调函数是then方法创建promise时,传入的回调函数,所以又返回到then方法promise传入的回调函数中,
3.由于这时this.status的状态是resolve,(this是这里p)所以执行then方法成功的回调,由于then中的回调函数是异步执行的,所以才在这里加了setTimeOut
4.异步调用()=>{throw ’123’}后,被catch捕获异常,直接调用promise对象的,reject方法。 改变了新创建的promise对象的状态,为(reject,同时data也赋值为‘123’)完毕。

这里好像没有调用this.callbacks.push()来绑定then的回调函数 ,那是因为是同步任务下,调用了成功的回调resolve, 将 p的状态变成了resolved。如果是promise是异步任务下呢?

    const result = p.then(value => {
            //1.返回字符串
            // return `hello promise`
            // 2.返回promise
            // return new Promise((resolve, reject) => {
            //     resolve("success")
            // })
            // 3.抛出异常
            throw '123'
        }, reason => {
            console.log(reason)
        })
  // then方法封装
    then(onResolved, onRejected) {
        const self = this
        // 判断回调函数参数
        if (typeof onRejected != 'function') {
            onRejected = reason => {
                throw reason;
            }
        } // 考虑异常穿透,没有指定reject,初始化reject为异常
        if (typeof onResolved != 'function') {
            onResolved = value => value
        } // 默认省略resolve,reject回调,初始化resolve,then也可以继续往下传
        return new Promise((resolve, reject) => {
            // 封装函数
            function callBack(onFun) {
                try {
                    // 获取回调函数执行结果 
                    let result = onFun(self.data)
                    //判断 结果是否是Promise对象
                    if (result instanceof Promise) {
                        result.then(v => {
                            resolve(v)
                        }, r => {
                            reject(r)
                        })
                    } else {//不是直接成功
                        //状态为成功
                        resolve(result)
                    }
                } catch (error) {
                    reject(error)
                }
            }
            // 调用回调函数 
            if (this.status === 'resolved') {
                setTimeout(() => {
                    callBack(onResolved)
                })
            }
            if (this.status === 'rejected') {
                setTimeout(() => {
                    callBack(onRejected)
                })
            }
            // 改变状态前,绑定回调函数
            if (this.status === 'preding') {
                // 保存回调函数
                this.callbacks.push({
                    onResolved: () => callBack(onResolved),
                    onRejected: () => callBack(onRejected)
                })
            }
        })
    }
    

异步任务下,then方法返回promise对象

如果是promise是异步任务下呢?(绝大多少情况下,promise都是封装异步的任务),由于同步任务执行完,才执行异步任务。所以 下面这种情况下:
p.then(…)时 p的状态是predding,

  1. p是predding方法,调用then方法时,会绑定then方法里的回调函数。
  2. 当同步任务都执行完之后,会调用异步任务,setTimeout方法,将p的状态变成resolve
    同时,将1中绑定then方法回调函数callBack(onResolved)进行执行, 将rs状态变成resolve, data= ‘hello promise’
         self.callbacks.forEach(item => {
                    item.onRejected(reason)
             })
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('OK')
            }, 1000)
            // reject('on no')
        });

        const rs = p.then(value => {
            //1.返回字符串
            return `hello promise`
            // 2.返回promise
          //  return new Promise((resolve, reject) => {
            //    reject("unsuccess")
            //})
            // 3.抛出异常
            // throw '123'
        }, reason => {
            // throw '123'
        })
        console.log(rs)

内置的promise
在这里插入图片描述
手写的promise:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值