背景
js在进行异步操作时,经常会使用promise来获取异步操作的返回结果,那promise内部究竟是如何实现的?
本文通过手写一个符合promise A+规范的promise类,来深入了解promise的实现逻辑。
什么是promise A+规范
promise A+规范,是一个开源的、可被开发者实现的标准promise规范,规定了实现一个标准的promise具体需要实现哪些功能。
promise A+规范相关术语:
- promise是一个包含了兼容promise规范then方法的对象或函数,
- thenable是一个包含了then方法的对象或函数。
- value是任何Javascript值。 (包括 undefined, thenable, promise等).
- exception是由throw表达式抛出来的值。
- reason是一个用于描述Promise被拒绝原因的值。
需要实现的功能有:
- promise状态,包括:pending, fulfilled或者rejected。
- then方法,then方法中包括onFulfilled和onRejected两个参数。
具体实现功能细则参考:promises A+规范
目前浏览器实现的promise,有哪些api呢
大概分为两种:
1、Class类上的方法
Promise.all, Promise.resolve, Promise.reject, Promise.race
2、实例上的方法
then/catch/finally
开始实现
我们平时使用Promise,写法大概是这样子:
let promise = new Promise(function(resolve, reject) {
// 如果做什么异步操作成功了
setTimeout(() => {
let isSuccess = true
if (isSuccess) {
resolve('接口返回成功了')
} else {
reject('接口返回失败了')
}
}, 1000)
})
promise.then(value => {
console.log('success', value)
}, error => {
console.log('error', error)
})
// 日志打印
// -> 接口返回成功了
那我们如何实现一个如上功能的promise?
如何实现一个promise
可以看到promise是一个类,里面传递一个带了resolve和reject参数的函数,这个函数叫做executor执行器,executor中包含了一个resolve函数和一个reject函数。
具体实现:
// 定义promise的三种状态常量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) {
// 初始化promise状态和value值
let that = this
that.status = PENDING
that.value = undefined
// resolve执行时,将状态置为成功态
function resolve(value) {
// 只有状态为pending时,status修改为fulfilled,同时更新value的值
if (that.status === PENDING) {
that.status = FULFILLED
that.value = value
}
}
// reject执行时,将状态置为失败态
function reject(reason) {
if (that.status === PENDING) {
that.status = REJECTED
that.value = reason
}
}
executor(resolve, reject)
}
Promise.prototype.then = function(onFulfilled, onRejected) {
let that = this
// 如果当前状态为已完成,则执行完成的回调
if (that.status === FULFILLED) {
onFulfilled(that.value)
}
// 如果当前状态为已失败,则执行失败的回调
if (that.status === REJECTED) {
onRejected(that.value)
}
}
一个简单的promise实现就已经完成,包含new Promise(executor: (resolve, reject) => void)的实现,并且支持then调用的逻辑来获取value或者reason。
但是该实现还不支持异步resolve或者reject状态
给promise添加发布/订阅者模式来支持异步更新状态
前面实现的promise,还有一个问题,就是executor执行器里的resolve如果延迟执行,比如延迟1000ms后再执行,当promise.then优先于resolve或者reject执行,此时该promise的status还是pending状态,不会执行then里面的onFulfilled和onRejected方法
所以这里我们要使用发布/订阅者模式,将promise.then里面的onFulfilled和onRejected两个监听方法存储起来,在promise的状态resolve或者reject时再通知对应的监听方法
添加发布/订阅者模式
// 定义promise的三种状态常量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) {
// 初始化promise状态和value值
let that = this
that.status = PENDING
that.value = undefined
// 初始化订阅resolve和rejecte方法的回调数组
that.onFulfilledCallbacks = []
that.onRejectedCallbacks = []
// resolve执行时,将状态置为成功态
function resolve(value) {
// 只有状态为pending时,status修改为fulfilled,同时更新value的值
if (that.status === PENDING) {
that.status = FULFILLED
that.value = value
// 执行订阅了resolve的回调方法
that.onFulfilledCallbacks.forEach(onFulfilled => onFulfilled(that.value))
}
}
// reject执行时,将状态置为失败态
function reject(reason) {
if (that.status === PENDING) {
that.status = REJECTED
that.value = reason
// 执行订阅了reject的回调方法
that.onRejectedCallbacks.forEach(onRejected => onRejected(that.value))
}
}
executor(resolve, reject)
}
Promise.prototype.then = function(onFulfilled, onRejected) {
let that = this
// 如果当前状态为已完成,则执行完成的回调
if (that.status === FULFILLED) {
onFulfilled(that.value)
}
// 如果当前状态为已失败,则执行失败的回调
if (that.status === REJECTED) {
onRejected(that.value)
}
// 如果当前状态还在pending,则将回调方法添加到订阅状态的回调中
if (that.status === PENDING) {
// 订阅resolve的回调
that.onFulfilledCallbacks.push(onFulfilled)
// 订阅reject的回调
that.onRejectedCallbacks.push(onRejected)
}
}
测试
好的,现在我们实现的promise已经非常强大了,可以写一个简单的测试用例,跑一下。
let promise1 = new Promise(function(resolve, reject) {
resolve('promise1-直接返回成功')
})
let promise2 = new Promise(function(resolve, reject) {
setTimeout(() => {
reject('promise2-异步返回成功')
}, 1000)
})
let promise3 = new Promise(function(resolve, reject) {
resolve('promise3-直接返回成功')
reject('promise3-直接返回失败')
})
promise1.then((value) => {
console.log('promise1-执行了onFulfilled', value)
}, (reason) => {
console.log('promise1-执行了onRejected', reason)
})
promise2.then((value) => {
console.log('promise2-执行了onFulfilled', value)
}, (reason) => {
console.log('promise2-执行了onRejected', reason)
})
promise3.then((value) => {
console.log('promise3-执行了onFulfilled', value)
}, (reason) => {
console.log('promise3-执行了onRejected', reason)
})
// 执行结果
// -> promise1-执行了onFulfilled promise1-接口返回成功了
// -> promise3-执行了onFulfilled promise3-接口返回成功了
// 1000ms后
// -> promise2-执行了onRejected promise2-异步返回成功
测试结果符合要求
promise1通过resolve,直接触发then里的onFulfilled,打印promise1-执行了onFulfilled promise1-接口返回成功了
promise2通过延迟触发reject,延迟1000ms后触发了onRejected,打印promise2-执行了onRejected
promise3先resolve再reject,由于resolve后当前promise状态会更新为fulfilled,所以后面再执行reject会无效,直接打印promise3-执行了onFulfilled
总结
目前我们的promise实现了以下功能:
- 实现了status状态,包含pending,fulfilled,rejected三种状态
- 实现了value的属性,可以通过then方法传入onFulfilled和onRejected中
- 实现了executor执行器以及里面的resolve和reject方法
- 实现了then方法,当状态更新为fulfilled或者rejected时,会将promise的value值传给then方法里的onFulfilled和onRejected
- 实现了异步更新状态时,通知then方法里面的onFulfilled和onRejected
这就是一个简单的符合promise A+规范promise实现,不过promise还有许多其他的功能特性和api,比如:Promise.resolve,Promise.reject,Promise.all等,我会在后面的文章中更新。
未完待续...