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 语句的时候被加入到微任务队列的。到底哪一种说法是正确的呢?

阅读 11.8k
5 个回答

都没问题。

关键在于,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。

发现老贺有答案了,比较喜欢这种讲事实摆依据的

新手上路,请多包涵

从抽象的层面来解读流程的话,个人认为是:

then的微任务是跟在前面Promise包装的任务之后的,如果Promise内是同步任务,则then就挂在当前第一轮事件循环的后面进行,如果Promise内部是一个异步任务,则该异步任务被注册为一个新的宏任务,则后面的then就会跟着这个宏任务之后执行。

具体来讲,当一个 promise 准备就绪时(即状态发生改变,从pending转到fullfilled时),它的 .then/catch/finally 处理程序就会被放入队列中。

推荐问题
宣传栏