如何实现一个 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