关于Promise.then()若返回值为Promise对象,会发起两个微任务队列

678 阅读2分钟

promise.jpg 目前我是刚转行,准备进入前端(原本专业是心理学,但心理学不好就业....),然后碰到这样这样一个Promise的面试题,觉得很有趣,特别分享一下

题目如下:

Promise.resolve().then(() => {
    console.log(0); // 
    return Promise.resolve(4); // 
}).then((res) => {
    console.log(res)
})
Promise.resolve().then(() => {
    console.log(1); // 
}).then(() => {
    console.log(2); // 
}).then(() => {
    console.log(3); // 
}).then(() => {
    console.log(5); // 
}).then(() => {
    console.log(6); // 
})

正确的输入结果是 0 1 2 3 4 5 6 我当初的算的结果是 0 1 2 4 3 5 6

思路

  • 我先说说我的思路(错误的)
  • 首先执行 console.log(0)
  • 然后执行return Promise.resolve(4),因为Promise.resolve(4)会发返回一个状态为‘fulfilled’的Promise对象,所以这里是return一个Promise对象,当Promise.then()return一个Promise对象时,会发起一个微任务队列,至于为什么是一个微任务队列,我手写一下Promise,来说明

可以不用看我前面手写的构造函数,直接看最下面的then函数,在我的想法里,当return一个Promise对象时,这个Promise对象会再次执行一下then方法,于是会再次发起一个微任务队列

  • 所以是 0 1 2 4 3
class newPromise {
    //构造方法
    constructor(executor) {
        //初始化状态和结果
        this.PromiseState = 'pending'
        this.PromiseResult = null

        const context = this

        //用于存放回调函数
        this.callbacks = []

        function resolve(value) {
            //判断状态是否为pending
            if (context.PromiseState !== 'pending') return

            context.PromiseState = 'fulfilled'
            context.PromiseResult = value
            //执行成功的回调函数
            setTimeout(() => {
                context.callbacks.forEach(element => {
                    element.onResolved(value)
                });
            })
        }

        function reject(reason) {
            if (context.PromiseState !== 'pending') return
            context.PromiseState = 'fulfilled'
            context.PromiseResult = reason

            //执行成功的回调函数
            setTimeout(() => {
                context.callbacks.forEach(element => {
                    element.onResolved(value)
                });
            })

        }
        try {
            executor(resolve, reject)
        } catch (reason) {
            reject(reason)
        }
    }

    //then方法
    then(onResolved, onRejected) {
        const context = this
        return new newPromise((resolve, reject) => {
            //封装一个函数
            function callback(type) {
                //type为onResolved或者onRejected
                let result = type(context.PromiseResult)

                if (result instanceof newPromise) {
                    //当返回值是一个Promise对象时,这个对象会再次执行一下then方法
                    result.then((value) => {
                        resolve(value)
                    }, (reason) => {
                        reject(reason)
                    })
                } else {
                    resolve(result)
                }
            }

            if (context.PromiseState === 'fulfilled') {
                setTimeout(() => {
                    callback(onResolved)
                }, 0)
            }
            if (context.PromiseState === 'rejected') {
                setTimeout(() => {
                    callback(onRejected)
                }, 0)
            }

            //new Promise()时,里面的异步任务还没有执行完
            //故此时状态为pending
            if (context.PromiseState == 'pending') {
                context.callbacks.push({
                    onResolved: function () {
                        callback(onResolved)
                    },
                    onRejected: function () {
                        callback(onRejected)
                    }
                })
            }
        })
    }
  • 但是最后的结果是0 1 2 3 4

  • 这就证明Promise.then()返回一个Promise对象时,会发起两个微任务队列。

  • 至于两个微任务是什么,

  • 参考这篇推文

  • 一个是当返回Promise对象时,这个Promise对象会再次执行一下then方法

  • 同时它还会再次隐式开启一个微任务