• 1.5k

promise then 的回调函数是在什么时候进入微任务队列的?

promise then 的回调函数是在遇到 resolve 语句的时候就被加入微任务队列,还是在遇到 then 语句的时候被加入到微任务队列?
在网上查了一些资料,发现有不同的说法:

  1. 比如在《深入理解ES6》中文版 244 页里是这么说的:“调用 resolve( ) 后会触发一个异步操作, 传入 then( ) 和 catch( ) 方法的函数会被添加到任务队列中并异步执行”,所以 then 方法的回调应该是在调用 resolve 后就被加入到队列中的?
  2. 对应的英文版原文是这么说的:“Calling resolve() triggers an asynchronous operation. Functions passed to then() and catch() are executed asynchronously, because these are also added to the job queue”
  3. 这个是知乎的回答:链接
  4. 这个是 StackOverflow 类似问题的回答:链接 ,答主在分析 event loop 的时候有这么一句:“The first then hooks up the first fulfillment handler, queuing a PromiseJobs job because the promise is already fulfilled”

1、2 都认为 then 的回调函数是在遇到 resolve 语句的时候就被加入微任务队列,3、4 都认为是在遇到 then 语句的时候被加入到微任务队列的。到底哪一种说法是正确的呢?

阅读 850
评论
    3 个回答
    • 9.6k

    都没问题。

    关键在于,then 是在 resolve 之前被调用的,还是 resolve 之后呢?

    thenresolve 之前,then 不会加微任务,而是缓存起来,resolve 看到缓存里又 then 的回调,于是加微任务。

    resolvethen 之前,resolve 的时候还没有任何回调要执行,自然不会加微任务。then 的时候发现已经 fullfilled ,于是直接加微任务。

    也就是说,他们都有可能加,也都有可能不加,就看调用时的 promise 的状态了。

    你的引用有些只说明了其一,但是说明里条件写得还是很清楚的,比如 4 里 "because the promise is already fulfilled"

      发表下我的意见,在我的理解里,Promise 的实现中,then 只会把回调放到一个数组里保存,所以我认为,reslove 后,才会进入微任务队列,存放callback 只是一个存放的操作

      当然 如果then的运行还没执行的时候,promise 已经reslove 了 ,我觉得会是同步的去把callback放入 microtasks的。

      总结起来就是 reslove -> then

        执行一个宏任务,过程中遇到微任务时,将其放到微任务的事件队列里,当前宏任务执行完成后,会查看微任务的事件队列,依次执行里面的微任务。如果还有宏任务的话,再重新开启宏任务……

        再结合一个例子看下:

        setTimeout(function () {
            console.log('a')
        });
        
        
        new Promise(function (resolve) {
            console.log('b');
        
            for (var i = 0; i < 10000; i++) {
                i == 99 && resolve();
            }
            
        }).then(function () {
            console.log('c')
        });
        
        console.log('d');
        
        // b 
        // d
        // c
        // a

        1.首先执行script下的宏任务,遇到setTimeout,将其放入宏任务的队列里。

        2.遇到Promisenew Promise直接执行,打印b。

        3.遇到then方法,是微任务,将其放到微任务的队列里。

        4.遇到console.log('d'),直接打印。

        5.本轮宏任务执行完毕,查看微任务,发现then方法里的函数,打印c。

        6.本轮event loop全部完成。

        7.下一轮循环,先执行宏任务,发现宏任务队列中有一个setTimeout,打印a。

          撰写回答

          登录后参与交流、获取后续更新提醒

          相似问题
          推荐文章