代码关键:

  • Promise A+ 主要规范(顶部注释)
  • then方法中对onFulfilledonRejected的处理
  • 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(); 
  1. 如果 promise then 回调是同步执行的,请问 foo() 和 bar() 函数谁先执行? 答案是:如果 trueOrFalse 为 true 则 foo() 先执行,bar() 后执行;否则 bar() 先执行,foo() 后执行。在大部分情况下,你没法预料到 trueOrFalse 的值,这也就意味着,你不能确定这段代码真正的执行顺序,这可能会导致一些难以想到的 bug。
  2. 如果 promise then 回调是异步执行的,请问 foo() 和 bar() 函数谁先执行? 答案一目了然,bar() 先执行,foo() 后执行。