在看 js 事件循环的时候,看到一个有趣的 promise then 执行顺序的题,想了好久,终于想明白了,这里记录一下。
大家先想下这里的执行顺序是什么。
new Promise(resolve => { // 1
setTimeout(()=>{ // 2
console.log(666); // 3
new Promise(resolve => { // 4
resolve(); // 5
}) // 6
.then(() => {console.log(777);}) // 7
}) // 8
resolve(); // 9
}) // 10
.then(() => { // 11
new Promise(resolve => { // 12
resolve(); // 13
}) // 14
.then(() => {console.log(111);}) // 15
.then(() => {console.log(222);});// 16
}) // 17
.then(() => { // 18
new Promise((resolve) => { // 19
resolve() // 20
}) // 21
.then(() => { // 22
new Promise((resolve) => { // 23
resolve() // 24
}) // 25
.then(() => {console.log(444)})// 26
}) // 27
.then(() => { // 28
console.log(555); // 29
}) // 30
}) // 31
.then(() => { // 32
console.log(333); // 33
}) // 34
===================
1,2,3,4,5,6,7
这里最疑惑的我想应该就是 333 为什么先比 444 和 555 执行了,这里首先要明确一点 promise then函数回调执行完毕后才会开始下一个 then 函数,当多个 then 链式调用的时候,如果一个 then 函数放入微任务队列,没有执行完,则之后的 then 都会先忽略,继续向下寻找同步任务继续执行。
首先,大家都知道 setTimeout 是宏任务,则一定在下一轮事件循环的时候才执行,则他的执行优先级最低,promise是同步任务,会先执行,promise.then() 是微任务,当遇到微任务的时候,会先放入微任务队列,继续向下寻找同步任务,同步任务执行完之后,开始执行微任务。
执行到 22 行逻辑:
这里当执行到 22 行时, then的参数整体作为一个函数放入微任务队列中,因为这里还没执行,所以 555 的 then 就暂时不执行,继续下一个 333 的 then 放入微任务队列,接下来没有同步任务了,开始执行微任务队列,当执行到 23 行的时候,这个微任务先执行 promise 同步函数,将then 444 又放入了 微任务队列,接下来没有课执行的同步任务了,则开始执行微任务队列 444 打印输出,至此, 22-27 行终于执行结束了,开始进入 下一个 then 微任务,并放入微任务队列,打印 555。
22-34 行执行结束:
进入下一个宏任务,执行第 3 行,同步任务,打印 666,执行 4-5 行,同步任务,进入 then,执行 7 行,微任务。