事件循环训练题
题目
console.log("script start"); // 宏任务
async function asyncFunc() {
console.log("asyncFunc start");
await Promise.resolve(); // 等待Promise解决
console.log("asyncFunc promise resolved");
}
asyncFunc(); // 调用async函数
setTimeout(function () {
console.log("setTimeout"); // 宏任务
}, 0);
Promise.resolve()
.then(function () {
console.log("promise1"); // 微任务
return new Promise((resolve) => {
setTimeout(() => {
console.log("setTimeout in promise1"); // 宏任务
resolve();
}, 0);
});
})
.then(function () {
console.log("promise2"); // 微任务
});
Promise.resolve().then(function () {
console.log("promise3"); // 微任务
});
console.log("script end"); // 宏任务
输出
script start
asyncFunc start
script end
promise1
promise3
asyncFunc promise resolved
undefined
setTimeout
setTimeout in promise1
promise2
解答
1. 为什么在输出asyncFunc start后会直接输入script end?
-
这是因为
JavaScript
的事件循环和任务队列的工作方式。当你调用一个异步函数时,它会立即开始执行,但是当遇到await关键字时,它会将后面的代码(在这个例子中是console.log("asyncFunc promise resolved")
)放入微任务队列,并立即返回控制权给主线程。 -
在主线程中,
console.log("script end")
是下一个要执行的语句,所以它会立即被执行。只有当主线程的所有同步任务都完成后,才会开始执行微任务队列中的任务。因此,console.log("asyncFunc promise resolved")
会在console.log("script end")
之后被执行。 -
这就是为什么你会看到"asyncFunc start"后面立即输出"script end",然后才输出"asyncFunc promise resolved"。
2. “在主线程中,console.log("script end")是下一个要执行的语句,所以它会立即被执行。”为什么不是setTimeout或者是Promise.resolve?
-
这是因为
JavaScript
的事件循环机制和任务队列的工作方式。JavaScript有一个主线程用于执行同步任务,以及一个任务队列用于存放异步任务。当主线程的所有同步任务都执行完毕后,才会去任务队列中取出任务来执行。 -
在你的代码中,
console.log("script end")
是一个同步任务,因此它会被立即执行。而setTimeout
和Promise.resolve().then
都是异步任务,它们会被放入任务队列中,等待主线程的同步任务都执行完毕后再执行。 -
此外,
setTimeout
和Promise.resolve().then
产生的任务分别属于宏任务和微任务。在每一轮事件循环中,主线程首先会执行所有的微任务,然后再执行一个宏任务。因此,即使setTimeout
和Promise.resolve().then
在代码中的位置在console.log("script end")之前,它们也会在console.log("script end")之后执行。