从0实现一个基本的Promise类(四)

836 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

前言

“手写Promise”系列作为前端常考点,深度检查了应聘者对Promise使用以及规范的理解,忏愧的是本人也是最近在完全通关这一模块。

此篇作为复习笔记,以及学习总结。

手写Promise包含以下知识点 👇:

  • Promise基础知识
  • Class 类
  • 改变this指向 (call、apply和bind)
  • 事件循环 Event Loop

其中Promise基础知识如果不了解或有遗忘的同学可以参考我这篇文章:《简单明了的Promise基本知识点》

在上文《从0实现一个基本的Promise类(三)》,我们加入了then方法中回调的保存,代码如下

class myPromise{
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
    constructor(func){
        this.PromiseState =  myPromise.PENDING
        this.PromiseResult = undefined
        this.onFulfilledCallbacks = []
        this.onRejectedCallbacks = []
        try{
            func(this.resolve.bind(this),this.reject.bind(this))
        }catch (e){
            this.reject(e)
        }
    }
    resolve(result){
        if(this.PromiseState == myPromise.PENDING){
            this.PromiseState = myPromise.FULFILLED
            this.PromiseResult = result
            setTimeout(()=>{
                this.onFulfilledCallbacks.forEach(callback=>{callback(result)})
            })
​
        }
    }
    reject(reason){
        if (this.PromiseState == myPromise.PENDING){
            this.PromiseState = myPromise.REJECTED
            this.PromiseResult = reason
            setTimeout(()=>{
                this.onRejectedCallbacks.forEach(callback=>{callback(reason)})
            })
​
        }
    }
    then(onFulfilled,onRejected){
        onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected == 'function' ? onRejected : reason =>{ throw reason }
        if (this.PromiseState == myPromise.FULFILLED){
            setTimeout(()=>{
                onFulfilled(this.PromiseResult)
            })
        }else if(this.PromiseState == myPromise.REJECTED){
            setTimeout(()=>{
                onRejected(this.PromiseResult)
            })
        }else if(this.PromiseState === myPromise.PENDING){
            this.onFulfilledCallbacks.push(onFulfilled)
            this.onRejectedCallbacks.push(onRejected)
        }
    }
}
​

本文将讲解以下知识点:

  1. then方法的链式调用
  2. resolvePromise方法

then方法的链式调用

等等! 我们似乎已经忘了Promise最纯粹的用意是什么了🤡

我们用Promise的目的难道不是解决**回调地狱**吗?

回想下我们在原生Promise中是如何解决**回调地狱**的:

let promise1 = new Promise((resolve,reject)=>{
    resolve(1)
}).then((res)=>{
    console.log(res,'first then')
    return ++res
}).then((res)=>{
    console.log(res,'second then')
})

控制台输出:

1 first then
2 second then

发现原生的promise是能够支持链式调用的,我们再试试前文中我们已完成的**myPromise**:

class myPromise{
    ....
}
let promise1 = new myPromise((resolve,reject)=>{
    resolve(1)
}).then((res)=>{
    console.log(res,'first then')
    return ++res
}).then((res)=>{
    console.log(res,'second then')
})

控制台结果报错:

}).then((res)=>{
  ^
TypeError: Cannot read property 'then' of undefined

为什么会找不到then方法呢🤔?看看下面这张promise执行图

vpPKUJ.png

从图中我们能看出then方法在执行后会返回一个新的promise对象,这也使得promise每次执行完then方法后还能够链式调用。

Promises/A+规范

then方法中关于返回新的promise对象的处理很复杂,我们在实现上参考Promise/A+规范👇

vAMqoD.png

其中2.2.7中明确规定:then必须返回一个promise。

 promise2 = promise1.then(onFulfilled, onRejected);

2.2.7.1 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)

2.2.7.2 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e

2.2.7.3 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值

2.2.7.4 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因

以上总结:不论 promise1 被 reject 还是被 resolve 时 promise2 都会执行 Promise 解决过程:[[Resolve]](promise2, x),只有出现异常时才会被 rejected。

注意这个2.2.7.1中的 [[Resolve]](promise2, x) ,在规范2.3中有更详细的执行过程,这部分过长在后续我们会讲解。目前我们先实现一个根据2.2.7、能够返回Promise的then方法。

返回一个Promise

提问:我们返回的这个新的promise中我们需要传递的执行函数是怎样的呢?🤔

首先在2.2.7.2 中:如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e

首先这一点说明了我们then方法中,执行onFulfilled 或者 onRejected这一步应当放在promise2的执行函数中。

为什么呢?

因为在这里我们还要加上对这俩个方法的错误捕捉,并在异常时调用promise2reject函数🤩so,动手👇

 then(onFulfilled,onRejected){
       ...
        const promise2 = new myPromise((resolve,reject)=>{
            if (this.PromiseState == myPromise.FULFILLED){
                setTimeout(()=>{
                    try {
                        onFulfilled(this.PromiseResult)
                    }catch (e){
                        reject(e)
                    }
                })
            }else if(this.PromiseState == myPromise.REJECTED){
                setTimeout(()=>{
                    try {
                        onRejected(this.PromiseResult)
                    }catch (e){
                        reject(e)
                    }
                })
            }else if(this.PromiseState === myPromise.PENDING){
                this.onFulfilledCallbacks.push(onFulfilled)
                this.onRejectedCallbacks.push(onRejected)
            }
        })
        return promise2
    }

接着根据2.2.7.1 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)

我们使用一个值去接受onFulfilledonRejected的返回值,并运行[[Resolve]](promise2, x),由于目前还没实现这个函数,我们先在外层加上一个resolvePromise的方法。

class myPromise{
 then(onFulfilled,onRejected){
        onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected == 'function' ? onRejected : reason =>{ throw reason }
        const promise2 = new myPromise((resolve,reject)=>{
            if (this.PromiseState == myPromise.FULFILLED){
                setTimeout(()=>{
                    try {
                        const value = onFulfilled(this.PromiseResult)
                        if (value != undefined){
                            resolvePromise(promise2,value)
                        }
                    }catch (e){
                        reject(e)
                    }
                })
            }else if(this.PromiseState == myPromise.REJECTED){
                setTimeout(()=>{
                    try {
                        const value = onRejected(this.PromiseResult)
                        if (value != undefined){
                            resolvePromise(promise2,value)
                        }
                    }catch (e){
                        reject(e)
                    }
                })
            }else if(this.PromiseState === myPromise.PENDING){
                this.onFulfilledCallbacks.push(onFulfilled)
                this.onRejectedCallbacks.push(onRejected)
            }
        })
        return promise2
    }
}
​
function resolvePromise(promise2, x){
​
}

最后,我们看看这俩点。2.2.7.3 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值

2.2.7.4 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因

我们知道在前文中有一个规定👇

  • onFulfilled 不为函数时,就将onFulfilled 修改为一个返回该值的函数
  • onRejected不为函数时,就将onRejected修改为一个抛出异常的函数

所以在2.2.7.3情况时,

const value = onFulfilled(this.PromiseResult)
if (value != undefined){
    resolvePromise(value)
}

变量value会得到一个返回值。并执行**resolvePromise**

而在2.2.7.4情况时,

 try {
     const value = onRejected(this.PromiseResult)
     if (value != undefined){
         resolvePromise(value)
     }
 }catch (e){
     reject(e)
 }

执行onReject函数会抛出一个异常,而被catch到从而执行reject函数。

总结:到此为止我们就完成了一个符合Promise/A+规范2.2.7的then方法了,并且能够链式调用。

目前实现的全部代码👇

class myPromise{
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
    constructor(func){
        this.PromiseState =  myPromise.PENDING
        this.PromiseResult = undefined
        this.onFulfilledCallbacks = []
        this.onRejectedCallbacks = []
        try{
            func(this.resolve.bind(this),this.reject.bind(this))
        }catch (e){
            this.reject(e)
        }
    }
    resolve(result){
        if(this.PromiseState == myPromise.PENDING){
            this.PromiseState = myPromise.FULFILLED
            this.PromiseResult = result
            setTimeout(()=>{
                this.onFulfilledCallbacks.forEach(callback=>{callback(result)})
            })

        }
    }
    reject(reason){
        if (this.PromiseState == myPromise.PENDING){
            this.PromiseState = myPromise.REJECTED
            this.PromiseResult = reason
            setTimeout(()=>{
                this.onRejectedCallbacks.forEach(callback=>{callback(reason)})
            })

        }
    }
    then(onFulfilled,onRejected){
        onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected == 'function' ? onRejected : reason =>{ throw reason }
        const promise2 = new myPromise((resolve,reject)=>{
            if (this.PromiseState == myPromise.FULFILLED){
                setTimeout(()=>{
                    try {
                        const value = onFulfilled(this.PromiseResult)
                        if (value != undefined){
                            resolvePromise(value)
                        }
                    }catch (e){
                        reject(e)
                    }
                })
            }else if(this.PromiseState == myPromise.REJECTED){
                setTimeout(()=>{
                    try {
                        const value = onRejected(this.PromiseResult)
                        if (value != undefined){
                            resolvePromise(value)
                        }
                    }catch (e){
                        reject(e)
                    }
                })
            }else if(this.PromiseState === myPromise.PENDING){
                this.onFulfilledCallbacks.push(onFulfilled)
                this.onRejectedCallbacks.push(onRejected)
            }
        })
        return promise2
    }
}
function resolvePromise(){

}

Next

由于将整个Promise细节堆在一起讲解篇幅会过长,我将文章也拆分为了五个小段进行描述。目的是为了让大家能够理解到不同的阶段,能够充分的消化并在实战中使用。

下一期从0实现一个基本的Promise类(五)同时也作为最后一章会讲述

  • Promise/A+规范2.3
  • 实现**resolvePromise**
  • 实现一个完整的符合、规范的、全部通过官方测试的Promise