代码关键:
- Promise A+ 主要规范(顶部注释)
then方法中对onFulfilled、onRejected的处理then方法是异步执行,原因是同步和异步共存的情况无法保证程序逻辑的一致性,模拟异步使用queueMicrotask而不是setTimeout。参考知乎。根据onFulfilled、onRejected执行结果,处理then返回的promise状态的方法
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const PENDDING = 'pendding'
/**
* Promise A+规范(简版)
* 1. promise对象有3种状态:pendding、fulfilled、rejected,只能从pendding到另外2种状态,状态只能改变一次
* 1. promise的状态在executor回调函数中改变状态
* 1. promise对象的then方法只会在后2种状态触发的时候执行
* 1. then方法有2个参数,分别是onFulfiiled、onRejected,必须是函数,不是函数会被忽略。分别在状态切换时被执行,并且参数为promise结果或者promise拒因
* 1. 同一个promise可以多次调用then方法,onFulfilled、onRejected方法按顺序执行
* 1. then方法的返回值如果是promise,那么下一个then会在这个promise返回后执行。如果不是promise,则被包裹成promise后返回
*/
export class Promise {
status = PENDDING
result = undefined
error = undefined
fulfilledList = []
rejectedList = []
resolve = (res) => {
if (this.status !== FULFILLED) {
this.status = FULFILLED
this.result = res
this.fulfilledList.forEach(onFulfilled => {
queueMicrotask(() => {
onFulfilled(this.result)
})
})
}
}
reject = (err) => {
if (this.status !== REJECTED) {
this.status = REJECTED
this.error = err
this.rejectedList.forEach(onRejected => {
queueMicrotask(() => {
onRejected(this.error)
})
})
}
}
constructor(executor) {
if (typeof executor !== 'function') {
throw TypeError('executor need to be a funciton!')
}
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
then = (onFulfilled = v => v, onRejected = v => v) => {
return new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
queueMicrotask(() => {
try {
const execResult = onFulfilled(this.result)
handleExecResult(execResult, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.status === REJECTED) {
queueMicrotask(() => {
try {
const execResult = onRejected(this.error)
handleExecResult(execResult, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.status === PENDDING) {
this.fulfilledList.push((result) => {
try {
const execResult = onFulfilled(result)
handleExecResult(execResult, resolve, reject)
} catch (error) {
reject(error)
}
})
this.rejectedList.push((error) => {
try {
const execResult = onRejected(error)
handleExecResult(execResult, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
}
/**
* 根据onFulfilled、onRejected执行结果,处理then返回的promise状态[简单版本]
* @param {*} result
* @param {*} thenReturnResolve
* @param {*} thenReturnReject
*/
const handleExecResult = (result, thenReturnResolve, thenReturnReject) => {
if (result instanceof Promise) {
result.then(thenReturnResolve, thenReturnReject)
} else {
thenReturnResolve(result)
}
}
/**
* 根据onFulfilled、onRejected执行结果,处理then返回的promise状态
* 并且判断onFulfilled、onRejected执行结果是不是then返回的promise,防止循环调用
* @param {*} promise
* @param {*} result
* @param {*} thenReturnResolve
* @param {*} thenReturnReject
*/
const handleExecResultEnhance = (promise, result, thenReturnResolve, thenReturnReject) => {
if (promise === result) {
thenReturnReject('Chaining cycle detected for Promise')
}
if (result instanceof Promise) {
result.then(thenReturnResolve, thenReturnReject)
} else {
thenReturnResolve(result)
}
}其他
Promise 的机制就是 then 回调函数必须异步执行。为什么?因为这样保障了代码执行顺序的一致性。
先看一个场景:
promise.then(function(){
if (trueOrFalse) {
// 同步执行
foo();
} else {
// 异步执行 (如:使用第三方库)
setTimeout(function(){
foo();
})
}
});
bar(); - 如果 promise then 回调是同步执行的,请问 foo() 和 bar() 函数谁先执行? 答案是:如果 trueOrFalse 为 true 则 foo() 先执行,bar() 后执行;否则 bar() 先执行,foo() 后执行。在大部分情况下,你没法预料到 trueOrFalse 的值,这也就意味着,你不能确定这段代码真正的执行顺序,这可能会导致一些难以想到的 bug。
- 如果 promise then 回调是异步执行的,请问 foo() 和 bar() 函数谁先执行? 答案一目了然,bar() 先执行,foo() 后执行。