携手创作,共同成长!这是我参与「掘金日新计划 · 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)
}
}
}
本文将讲解以下知识点:
- then方法的链式调用
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执行图
从图中我们能看出then方法在执行后会返回一个新的promise对象,这也使得promise每次执行完then方法后还能够链式调用。
Promises/A+规范
then方法中关于返回新的promise对象的处理很复杂,我们在实现上参考Promise/A+规范👇
其中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的执行函数中。
为什么呢?
因为在这里我们还要加上对这俩个方法的错误捕捉,并在异常时调用promise2的reject函数🤩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)
我们使用一个值去接受onFulfilled 和 onRejected的返回值,并运行[[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类