T6
node.js
js
setTimeout(() => { //setTimeout 1
console.log('setTimeout start');
Promise.resolve() // Promises
.then(() => console.log('promise resolve1'))
.then(() => console.log('promise resolve2'))
.then(() => console.log('promise resolve3'))
.then(() => console.log('promise resolve4'))
new Promise((resolve) => { // newPromise
console.log('promise1 start');
resolve()
}).then(() => {
console.log('promise1 end');
});
setTimeout(() => { // setTimeout 2
console.log('inner setTimeout')
})
console.log('setTimeout end');
}, 0);
function promise2() { // promise2
return new Promise((resolve) => {
console.log('promise2');
resolve();
})
}
async function async1() {
console.log('async1 start');
await promise2();
console.log('async1 end');
}
async1();
console.log('script end');
答案
js
async1 start
promise2
script end
async1 end
setTimeout start
promise1 start
setTimeout end
promise resolve1
promise1 end
promise resolve2
promise resolve3
promise resolve4
inner setTimeout
- 首先script整体作为同步任务执行,遇到setTimeout定时宏任务时交给定时线程去执行,其结果会放入宏任务队列,主线程挂起当前异步任务继续执行后面的代码。
- 执行async1(),async1函数入栈,并为当前函数提供一些变量上下文。首先打印
async1 start
,遇到await promise2
,会执行new Promise()
其也是个同步代码,所以会打印promise2
,接着会执行resolve()
,它返回的是个promise,然后回到async1函数内部,await其实是个语法糖,后面的代码会作为promise的then代码块执行,而then会当做微任务进入微任务队列(promise不清楚的可以看我『异步编程』一文),async1执行完后出栈。 - 执行
console.log(script end)
,打印,然后出栈,第一轮同步任务执行完毕。 - 同步任务执行完后先看有没有微任务,第2步await后面的语句已经被放入微任务队列了,执行后打印
async1 end
,微任务队列清空。 - 这里没有涉及到视图更新等等。
- 主线程接着从任务队列中选取一个最老的宏任务(MacroTask)来执行,这里任务队列中只有一个
setTimeout定时任务
,首先会判断执行它的时机到了没,如果没到由于没有其他宏任务了,主线程什么都不会做。反之执行其会首先打印setTimeout start
。接着执行Promise.resolve()
其返回promise是个微任务会放入微任务队列,接着new Promise()
执行打印promise1 start
,内部也会resolve返回promise也是个微任务放入微任务队列。接着就是setTimeout放入宏任务队列,最后执行setTimeout end
。 - MacroTask执行完毕,清空所有的MircoTask。首先执行
promise resolve1
,而后的then也是个微任务会被放入当前微任务队列。接着执行promise1 end
,接下来又会执行promise resolve2
,它也一样返回微任务(和前面重复步骤)直到执行完后面所有的then。 - MircoTask执行完后MacroTask Queue就剩下一个setTimeout任务了,合适的时机打印
inner setTimeout
。