简单实现一个 Promise
Posted 彭博
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单实现一个 Promise相关的知识,希望对你有一定的参考价值。
如何实现一个 Promise/A+
Promise 应该具备什么属性?
- A promise must be in one of three states: pending, fulfilled, or rejected[1].
- 同时根据 promise 的三种状态,需要有两个属性用于存储 promise 的返回结果,value, reason
Promise 实例是一个 thenable 的对象,即必须包含一个 then 方法
const PENDING = \'pending\' const FULLFILLED = \'fulfilled\' const REJECTED = \'rejected\' class PbPromise{ constructor(){ this.state = PENDING this.value = undefined this.reason = null } then(){ } }
如何实例化一个 Promise 实例
- 通过
new Promise(fn)
实例化一个Promise
实例,其中fn
用于改变当前Promsise的状态,即Promsie
实例在实例化时需要接受一个函数类型的参数 ,executor
,这个函数用于改变当前Promise 的状态。该函数是在promise 实例化过程中同步执行的。 - 外部的函数如何改变
Promsie
内部的状态?这需要Promise
与该函数产生交互,即需要Promise
提供改变其状态的方法给executor
,由于Promise
会有两种状态的变化,因此该方法需要接受两个方法分别处理不同的状态 -executor(resolve, reject)
const PENDING = \'pending\'
const FULLFILLED = \'fulfilled\'
const REJECTED = \'rejected\'
class PbPromise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = null
+ // 用于将当前 Promise 状态转换为 FULLFILLED
+ const resolve = () => {
+ // 状态只能转变一次
+ if(this.state !== PENDING) return
+ this.state = FULLFILLED
+ }
+ // 用于将当前 Promise 状态转换为 REJECTED
+ const reject = () => {
+ // 状态只能转变一次
+ if(this.state !== PENDING) return
+ this.state = REJECTED
+ }
+ // 此时外部通过 调用 resolve 或者 reject 就可以改变 Promise 内部的状态
+ executor(resolve, reject)
}
then(){
}
}
then 方法进行回调接收
Promse
通过then
来预设状态(state)发生变化之后的回调函数。then
接受两个函数作为参数:promise.then(onFulfilled, onRejected)
,其中onFulfilled
为fulfilled状态的回调,onRejected
为rejected之后的回调。
const PENDING = \'pending\'
const FULLFILLED = \'fulfilled\'
const REJECTED = \'rejected\'
class PbPromise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = null
+ this.onFulfilledList = []
+ this.onRejectedList = []
// 用于将当前 Promise 状态转换为 FULLFILLED
const resolve = value => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = FULLFILLED
this.value = value
+ // 状态发生变化 要 回调 then 存储的回调函数
+ this.onFulfilledList.forEach(f => f())
}
// 用于将当前 Promise 状态转换为 REJECTED
const reject = reason => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = REJECTED
this.reason = reason
+ // 状态发生变化 要 回调 then 存储的回调函数
+ this.onRejectedList.forEach(f => f())
}
// 此时外部通过 调用 resolve 或者 reject 就可以改变 Promise 内部的状态
executor(resolve, reject)
}
- then(){
- }
+ // 接受回调函数,并进行执行 / 存储
+ then(onFulfilled, onRejected){
+ // 检查当前状态,非 PENDING 直接执行回调函数
+ if(this.state === FULLFILLED){
+ return onFulfilled(this.value)
+ }
+ if(this.state === REJECTED){
+ return onRejected(this.reason)
+ }
+
+ // PENDING 状态需要将回调函数存储起来,此时需要两个列表来存储回调函数
+ // onFulfilledList onRejectedList
+ // 这些回调函数应该在 resolve 方法 或者 reject 方法调用之后立即调用
+ this.onFulfilledList.push(onFulfilled)
+ this.onRejectedList.push(onRejected)
}
}
then
方法要返回一个新的Promise
,用于实现链式调用,新的Promsie
的状态要在当前then
中传入的回调函数执行时变化,用于保证then
之间回调函数的执行顺序
class PbPromise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = null
this.onFulfilledList = []
this.onRejectedList = []
// 用于将当前 Promise 状态转换为 FULLFILLED
const resolve = value => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = FULLFILLED
this.value = value
// 状态发生变化 要 回调 then 存储的回调函数
this.onFulfilledList.forEach(f => f())
}
// 用于将当前 Promise 状态转换为 REJECTED
const reject = reason => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = REJECTED
this.reason = reason
// 状态发生变化 要 回调 then 存储的回调函数
this.onRejectedList.forEach(f => f())
}
// 此时外部通过 调用 resolve 或者 reject 就可以改变 Promise 内部的状态
executor(resolve, reject)
}
// 接受回调函数,并进行执行 / 存储
then(onFulfilled, onRejected){
+ return new PbPromise((resolve, reject) => {
// 检查当前状态,非 PENDING 直接执行回调函数
if(this.state === FULLFILLED){
- return onFulfilled(this.value)
+ const value = onFulfilled(this.value)
+ return resolve(value)
}
if(this.state === REJECTED){
- return onRejected(this.reason)
+ const reason = onRejected(this.reason)
+ // 注意这里是 resove
+ return resolve(reason)
}
// PENDING 状态需要将回调函数存储起来,此时需要两个列表来存储回调函数
// onFulfilledList onRejectedList
// 这些回调函数应该在 resolve 方法 或者 reject 方法调用之后立即调用
- this.onFulfilledList.push(onFulfilled)
- this.onRejectedList.push(onRejected)
+ this.onFulfilledList.push(() => {
+ const value = onFulfilled(this.value)
+ resolve(value)
+ })
+ this.onRejectedList.push(() => {
+ const reason = onRejected(this.reason)
+ // 注意这里是 resove
+ resolve(reason)
+ })
+ })
}
}
如何处理 返回值为 Promise 的场景?
- 当当前Promise 的返回值 仍然是一个 Promise 时,当前 then 方法仍然要将返回的Promise的值返回,即要保证 then 中的回调函数拿到的结果不是一个 thenable 的数据
class PbPromise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = null
this.onFulfilledList = []
this.onRejectedList = []
// 用于将当前 Promise 状态转换为 FULLFILLED
const resolve = value => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = FULLFILLED
this.value = value
// 状态发生变化 要 回调 then 存储的回调函数
this.onFulfilledList.forEach(f => f())
}
// 用于将当前 Promise 状态转换为 REJECTED
const reject = reason => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = REJECTED
this.reason = reason
// 状态发生变化 要 回调 then 存储的回调函数
this.onRejectedList.forEach(f => f())
}
// 此时外部通过 调用 resolve 或者 reject 就可以改变 Promise 内部的状态
executor(resolve, reject)
}
// 接受回调函数,并进行执行 / 存储
then(onFulfilled, onRejected){
return new PbPromise((resolve, reject) => {
// 检查当前状态,非 PENDING 直接执行回调函数
if(this.state === FULLFILLED){
const value = onFulfilled(this.value)
+ // 处理返回值为 Promise 的场景
+ if(typeof value === \'object\' && typeof value.then === \'function\') {
+ return value.then(resolve, reject)
+ }
return resolve(value)
}
if(this.state === REJECTED){
const reason = onRejected(this.reason)
+ // 处理返回值为 Promise 的场景
+ if(typeof reason === \'object\' && typeof reason.then === \'function\') {
+ return reason.then(resolve, reject)
+ }
return resolve(reason)
}
// PENDING 状态需要将回调函数存储起来,此时需要两个列表来存储回调函数
// onFulfilledList onRejectedList
// 这些回调函数应该在 resolve 方法 或者 reject 方法调用之后立即调用
this.onFulfilledList.push(() => {
const value = onFulfilled(this.value)
+ // 处理返回值为 Promise 的场景
+ if(typeof value === \'object\' && typeof value.then === \'function\') {
+ return value.then(resolve, reject)
+ }
resolve(value)
})
this.onRejectedList.push(() => {
const reason = onRejected(this.reason)
+ // 处理返回值为 Promise 的场景
+ if(typeof reason === \'object\' && typeof reason.then === \'function\') {
+ return reason.then(resolve, reject)
+ }
resolve(reason)
})
})
}
}
代码异常的 catch
- 通过 try catch 将异常捕获并抛出
class PbPromise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = null
this.onFulfilledList = []
this.onRejectedList = []
// 用于将当前 Promise 状态转换为 FULLFILLED
const resolve = value => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = FULLFILLED
this.value = value
// 状态发生变化 要 回调 then 存储的回调函数
this.onFulfilledList.forEach(f => f())
}
// 用于将当前 Promise 状态转换为 REJECTED
const reject = reason => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = REJECTED
this.reason = reason
// 状态发生变化 要 回调 then 存储的回调函数
this.onRejectedList.forEach(f => f())
}
// 此时外部通过 调用 resolve 或者 reject 就可以改变 Promise 内部的状态
executor(resolve, reject)
}
// 接受回调函数,并进行执行 / 存储
then(onFulfilled, onRejected){
return new PbPromise((resolve, reject) => {
// 检查当前状态,非 PENDING 直接执行回调函数
if(this.state === FULLFILLED){
+ try {
const value = onFulfilled(this.value)
// 处理返回值为 Promise 的场景
if(typeof value === \'object\' && typeof value.then === \'function\') {
return value.then(resolve, reject)
}
return resolve(value)
+ }catch(e){
+ return reject(e)
+ }
}
if(this.state === REJECTED){
+ try{
const reason = onRejected(this.reason)
// 处理返回值为 Promise 的场景
if(typeof reason === \'object\' && typeof reason.then === \'function\') {
return reason.then(resolve, reject)
}
return resolve(reason)
+ }catch(e){
+ return reject(reason)
+ }
}
// PENDING 状态需要将回调函数存储起来,此时需要两个列表来存储回调函数
// onFulfilledList onRejectedList
// 这些回调函数应该在 resolve 方法 或者 reject 方法调用之后立即调用
this.onFulfilledList.push(() => {
+ try{
const value = onFulfilled(this.value)
// 处理返回值为 Promise 的场景
if(typeof value === \'object\' && typeof value.then === \'function\') {
return value.then(resolve, reject)
}
resolve(value)
+ }catch(e){
+ reject(e)
+ }
})
this.onRejectedList.push(() => {
+ try{
const reason = onRejected(this.reason)
// 处理返回值为 Promise 的场景
if(typeof reason === \'object\' && typeof reason.then === \'function\') {
return reason.then(resolve, reject)
}
resolve(reason)
+ }catch(e){
+ reject(e)
+ }
})
})
}
}
代码化简
- 抽离then 方法中调用回调函数的逻辑
- 抽离 try catch
class PbPromise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = null
this.onFulfilledList = []
this.onRejectedList = []
// 用于将当前 Promise 状态转换为 FULLFILLED
const resolve = value => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = FULLFILLED
this.value = value
// 状态发生变化 要 回调 then 存储的回调函数
this.onFulfilledList.forEach(f => f())
}
// 用于将当前 Promise 状态转换为 REJECTED
const reject = reason => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = REJECTED
this.reason = reason
// 状态发生变化 要 回调 then 存储的回调函数
this.onRejectedList.forEach(f => f())
}
// 此时外部通过 调用 resolve 或者 reject 就可以改变 Promise 内部的状态
executor(resolve, reject)
}
// 接受回调函数,并进行执行 / 存储
then(onFulfilled, onRejected){
return new PbPromise((resolve, reject) => {
// 检查当前状态,非 PENDING 直接执行回调函数
if(this.state === FULLFILLED){
- try {
- const value = onFulfilled(this.value)
- // 处理返回值为 Promise 的场景
- if(typeof value === \'object\' && typeof value.then === \'function\') {
- return value.then(resolve, reject)
- }
- return resolve(value)
- }catch(e){
- return reject(e)
- }
+ return this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject)()
}
if(this.state === REJECTED){
- try{
- const reason = onRejected(this.reason)
- // 处理返回值为 Promise 的场景
- if(typeof reason === \'object\' && typeof reason.then === \'function\') {
- return reason.then(resolve, reject)
- }
- return resolve(reason)
- }catch(e){
- return reject(reason)
- }
+ return this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject)()
}
// PENDING 状态需要将回调函数存储起来,此时需要两个列表来存储回调函数
// onFulfilledList onRejectedList
// 这些回调函数应该在 resolve 方法 或者 reject 方法调用之后立即调用
- this.onFulfilledList.push(() => {
- try{
- const value = onFulfilled(this.value)
- // 处理返回值为 Promise 的场景
- if(typeof value === \'object\' && typeof value.then === \'function\') {
- return value.then(resolve, reject)
- }
- resolve(value)
- }catch(e){
- reject(e)
- }
- })
- this.onRejectedList.push(() => {
- try{
- const reason = onRejected(this.reason)
- // 处理返回值为 Promise 的场景
- if(typeof reason === \'object\' && typeof reason.then === \'function\') {
- return reason.then(resolve, reject)
- }
- resolve(reason)
- }catch(e){
- reject(e)
- }
- })
+ this.onFulfilledList.push(this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject))
+ this.onRejectedList.push(this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject))
})
}
+ handleResolve(onFulfilled, resolve, reject){
+ return () => {
+ const value = onFulfilled(this.value)
+ // 处理返回值为 Promise 的场景
+ if(typeof value === \'object\' && typeof value.then === \'function\') {
+ return value.then(resolve, reject)
+ }
+ resolve(value)
+ }
+ }
+ handleReject(onRejected, resolve, reject){
+ return () => {
+ const reason = onRejected(this.reason)
+ // 处理返回值为 Promise 的场景
+ if(typeof reason === \'object\' && typeof reason.then === \'function\') {
+ return reason.then(resolve, reject)
+ }
+ resolve(reason)
+ }
+ }
+ tryCatchFn(fn, catchFn){
+ return () => {
+ try {
+ fn()
+ }catch (e){
+ catchFn(e)
+ }
+ }
+ }
}
then 方法中的回调函数必须是异步执行的
- then方法中回调函数的异步执行,可以通过 setTimeout setImmediate,MutationObserver, process.nextTick 来进行模拟,注意这里只是进行异步调用的模拟,并不是说原生的 promise就是通过以上方式实现。因为涉及到微任务与宏任务之间的执行顺序,这里并不能完全的模拟实现
class PbPromise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = null
this.onFulfilledList = []
this.onRejectedList = []
// 用于将当前 Promise 状态转换为 FULLFILLED
const resolve = value => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = FULLFILLED
this.value = value
// 状态发生变化 要 回调 then 存储的回调函数
this.onFulfilledList.forEach(f => f())
}
// 用于将当前 Promise 状态转换为 REJECTED
const reject = reason => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = REJECTED
this.reason = reason
// 状态发生变化 要 回调 then 存储的回调函数
this.onRejectedList.forEach(f => f())
}
// 此时外部通过 调用 resolve 或者 reject 就可以改变 Promise 内部的状态
executor(resolve, reject)
}
// 接受回调函数,并进行执行 / 存储
then(onFulfilled, onRejected){
return new PbPromise((resolve, reject) => {
// 检查当前状态,非 PENDING 直接执行回调函数
if(this.state === FULLFILLED){
- return this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject)()
+ // 通过 setTimeout 来模拟实现异步调用
+ setTimeout(this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject))
}
if(this.state === REJECTED){
- return this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject)()
+ // 通过 setTimeout 来模拟实现异步调用
+ setTimeout(this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject))
}
// PENDING 状态需要将回调函数存储起来,此时需要两个列表来存储回调函数
// onFulfilledList onRejectedList
// 这些回调函数应该在 resolve 方法 或者 reject 方法调用之后立即调用
this.onFulfilledList.push(this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject))
this.onRejectedList.push(this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject))
})
}
handleResolve(onFulfilled, resolve, reject){
return () => {
const value = onFulfilled(this.value)
// 处理返回值为 Promise 的场景
if(typeof value === \'object\' && typeof value.then === \'function\') {
return value.then(resolve, reject)
}
resolve(value)
}
}
handleReject(onRejected, resolve, reject){
return () => {
const reason = onRejected(this.reason)
// 处理返回值为 Promise 的场景
if(typeof reason === \'object\' && typeof reason.then === \'function\') {
return reason.then(resolve, reject)
}
resolve(reason)
}
}
tryCatchFn(fn, catchFn){
return () => {
try {
fn()
}catch (e){
catchFn(e)
}
}
}
}
onRejected, onFulfilled 可选 以及 reject 穿透
- onRejected, onFulfilled 两个回调函数是可选的,因此当前 promise 返回的数据 resolve 或者reject 之后,value, reason 应该能够传递给接下来的 onFulfilled, onRejected,方法进行处理。
+ const NOOP = () => {}
class PbPromise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = null
this.onFulfilledList = []
this.onRejectedList = []
// 用于将当前 Promise 状态转换为 FULLFILLED
const resolve = value => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = FULLFILLED
this.value = value
// 状态发生变化 要 回调 then 存储的回调函数
this.onFulfilledList.forEach(f => f())
}
// 用于将当前 Promise 状态转换为 REJECTED
const reject = reason => {
// 状态只能转变一次
if(this.state !== PENDING) return
this.state = REJECTED
this.reason = reason
// 状态发生变化 要 回调 then 存储的回调函数
this.onRejectedList.forEach(f => f())
}
// 此时外部通过 调用 resolve 或者 reject 就可以改变 Promise 内部的状态
executor(resolve, reject)
}
// 接受回调函数,并进行执行 / 存储
- then(onFulfilled, onRejected){
+ then(onFulfilled = NOOP, onRejected = NOOP){
+ if(typeof onFulfilled !== \'function\') onFulfilled = NOOP;
+ if(typeof onRejected !== \'function\') onRejected = NOOP;
return new PbPromise((resolve, reject) => {
// 检查当前状态,非 PENDING 直接执行回调函数
if(this.state === FULLFILLED){
// 通过 setTimeout 来模拟实现异步调用
setTimeout(this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject))
}
if(this.state === REJECTED){
// 通过 setTimeout 来模拟实现异步调用
setTimeout(this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject))
}
// PENDING 状态需要将回调函数存储起来,此时需要两个列表来存储回调函数
// onFulfilledList onRejectedList
// 这些回调函数应该在 resolve 方法 或者 reject 方法调用之后立即调用
this.onFulfilledList.push(this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject))
this.onRejectedList.push(this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject))
})
}
handleResolve(onFulfilled, resolve, reject){
return () => {
+ // resolve 穿透
+ if(onFulfilled === NOOP) return resolve(this.value)
const value = onFulfilled(this.value)
// 处理返回值为 Promise 的场景
if(typeof value === \'object\' && typeof value.then === \'function\') {
return value.then(resolve, reject)
}
resolve(value)
}
}
handleReject(onRejected, resolve, reject){
return () => {
+ // reject 穿透
+ if(onRejected === NOOP) return reject(this.reason)
const reason = onRejected(this.reason)
// 处理返回值为 Promise 的场景
if(typeof reason === \'object\' && typeof reason.then === \'function\') {
return reason.then(resolve, reject)
}
resolve(reason)
}
}
tryCatchFn(fn, catchFn){
return () => {
try {
fn()
}catch (e){
catchFn(e)
}
}
}
}
其他
- 这里仅仅是对Promise 的一种简单粗略的实现,
- 值得注意的是[1]中有说明 promise 在事件循环中的位置可能会根据实现有所不同
[1] Promise/A+ https://promisesaplus.com
[2] https://promisesaplus.com/#notes
以上是关于简单实现一个 Promise的主要内容,如果未能解决你的问题,请参考以下文章