手撕Promise系列四

87 阅读3分钟

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

题外话

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

冷知识:你晕不晕车,跟你吃没吃饭,没有一点关系,唯一的区别就是:

你吃饭了,吐的是食物;

你没吃饭,吐的是胆汁。

所以下回谁再拿我晕车阻止我吃饭你看着,哼哼

前情回顾

promise里面最复杂就是then方法的实现,在promise系列里面我们首先完成了

Promise的基本搭建

then的一步处理和多次调用

then的链式调用

这些是我们在前三篇中已经完成的部分,那么还有什么是我们目前还没有实现的呢

正文

我们先看一个例子

let promise = new Promise((resolve, reject) => {
    resolve(1)
})

let p1 = promise.then(resp => {
    console.log(resp);
    return p1
})

此时会抛出一个错误TypeError: Chaining cycle detected for promise #<Promise> 我们也需要加工一下我们自己封装的MyPromise

解决promise循环调用问题

我们可以判断返回的promise和返回值result是否相等,如果相等就说明返回了自己,就需要执行reject将失败的结果抛出。

  1. 对判断类型的函数新接收一个参数,是返回的promise对象,用来和返回值result进行对比
  2. 我们会发现在new Promise我们是获取不到promise对象的,因为promise是在Promise执行之后才能获取得到,所以我们需要将获取promise的代码处理成异步代码
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENDING
    resp = undefined
    error = undefined
    successCallback = []
    failCallback = []
    resolve = (resp) => {
        if (this.status !== PENDING) return
        this.status = FULFILLED
        this.resp = resp
        while (this.successCallback.length) this.successCallback.shift()(this.resp)
    }
    reject = (error) => {
        if (this.status !== PENDING) return
        this.status = REJECTED
        this.error = error
        while (this.failCallback.length) this.failCallback.shift()(this.error)
    }
    then(successCallback, failCallback) {
        let promise = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                //3. 因为new Promise是立即执行的,在Promise执行过程中获取不到执行结果promise,所以使用异步处理在Promise执行之后,获取执行结果promise
                setTimeout(() => {
                    let result = successCallback(this.resp)
                    //2. 将promise传入
                    returnPromise(promise, result, resolve, reject)
                }, 0)
            } else if (this.status === REJECTED) {
                failCallback(this.error)
            } else {
                this.successCallback.push(successCallback)
                this.failCallback.push(failCallback)
            }
        })
        return promise
    }
}

function returnPromise(promise, result, resolve, reject) {
    //1. 对判断类型的函数新增一个参数promise,对promise和result返回值进行判断,如果promise和result相等,说明返回是自己本身,使用reject抛出错误
    if (promise === result) {
        return reject('TypeError: Chaining cycle detected for promise #<Promise>')
    }
    if (result instanceof MyPromise) {
        result.then(resolve, reject)
    } else {
        resolve(result)
    }
}

结束

到目前为止我们对then方法来说解决了基础搭建,接收返回值,多次调用,链式调用,循环调用的问题,那么如果我们在立即执行new Promise这个执行器里面代码执行出现问题呢?then方法回调函数类型代码出现问题呢?失败reject回调函数链式调用?then方法的参数是不是可选参数?

这些我们将在后面的博客里面进行详细讲解~~~~