手撕Promise系列二

110 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

题外话

这个疫情啊,真滴是服气了,居家快一个月了,居家不是办公就是做饭,脑子都快麻木了,为了活跃自己的大脑,也为了帮助大家增长知识,我给大家分享一点冷知识,嘿嘿嘿……

冷知识:中含有大量盐类和多种元素,其中许多元素是人体所需要的。但海水中各种物质浓度太高,远远超过饮用水卫生标准,如果大量饮用,会导致某些元素过量进入人体,影响人体正常的生理功能,严重的还会引起中毒

所以去海边一定不要尝试喝海水啊~~~~~~~~~

前情回顾

上一篇我们说到then接收两个回调函数,这里我将上一篇的代码展示如下,我们可以验证一下代码的正确性

new MyPromise((resolve, reject) => {
    resolve('成功')
}).then(resp => {
    console.log(resp);
}, err => {
    console.log(err);
})

//成功

正题

Promise.prototype.then()异步处理

我们上面验证了同步代码是可以回调并且接收的,接下来我们看看promise中的异步代码如何接收 需要在promise对象拿到返回值之后再接收返回值

  1. 我们首先定义一个参数用来存储临时存储成功或者失败的回调函数
  2. 等待异步代码执行resolve或者reject之后再执行存储的回调函数接收返回值
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENDING
    resp = undefined
    error = undefined
    //1.1 定义变量用来临时存储成功或者失败的回调函数
    successCallback = undefined
    failCallback = undefined
    
    resolve = (resp) => {
        if (this.staus !== PENDING) return
        this.status = FULFILLED
        this.resp = resp
        //2 判断代码是否是成功回调的,如果是九江回调的返回值一并返回
        this.successCallback && this.successCallback(this.resp)
    }
    reject = (error) => {
        if (this.staus !== PENDING) return
        this.status = REJECTED
        this.error = error
        //同理
        this.failCallback && this.failCallback(this.error)
    }
    then(successCallback, failCallback) {
        if (this.status === FULFILLED) {
            successCallback(this.resp)
        } else if (this.status === REJECTED) {
            failCallback(this.error)
        } else {
            //1.2 将回调函数临时存储起来
            this.successCallback = successCallback
            this.failCallback = failCallback
        }
    }
}

验证

new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('成功')
    })
}).then(resp => {
    console.log(resp);
}, err => {
    console.log(err);
})

Promise.prototype.then()多次调用处理

上面我们对promise里面存在异步代码进行了处理,接着我们对多次调用进行处理 什么是多次调用的?

let promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('成功')
    })
})
promise.then(resp => {
    console.log(1);
    console.log(resp);
})
promise.then(resp => {
    console.log(2);
    console.log(resp);
})
promise.then(resp => {
    console.log(3);
    console.log(resp);
})

上述这段代码如果我们采用上面的MyPromise执行的话,我们输出的数字打印只会打印1,原因就是我们successCllback和failCallback只临时保存了一次,所以只会保存我们的第一个then的返回值。接下来我们开始完善我们的MyPromise

  1. 我们需要保存所有的调用回调函数,那么successCallback和failCallback就需要是个数组
  2. 将所有的回调函数push进临时存储数组
  3. 依次循环临时存储的数组,执行一个就删除一个
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENDING
    resp = undefined
    error = undefined
    //1. 更改临时存储为数组
    successCallback = []
    failCallback = []
    resolve = (resp) => {
        if (this.staus !== PENDING) return
        this.status = FULFILLED
        this.resp = resp
        // this.successCallback && this.successCallback(this.resp)
        //3. 依次循环临时保存数组,执行完一个就弹出一个,并将返回值返回
        while (this.successCallback.length) this.successCallback.shift()(this.resp)
    }
    reject = (error) => {
        if (this.staus !== PENDING) return
        this.status = REJECTED
        this.error = error
        // this.failCallback && this.failCallback(this.error)
        while (this.failCallback.length) this.failCallback.shift()(this.error)
    }
    then(successCallback, failCallback) {
        if (this.status === FULFILLED) {
            successCallback(this.resp)
        } else if (this.status === REJECTED) {
            failCallback(this.error)
        } else {
            //2. 将回调函数一次push进入临时保存数组
            this.successCallback.push(successCallback)
            this.failCallback.push(failCallback)
        }
    }
}