对于 JS 事件循环,之前都是看文章有个大致的了解,对于经典的面试题只是看了下,大致知道是什么意思,这次面试碰到了,面试完了仔细看了下文章,当时应该是搞错了,问题中坑还是很多的,用题目的方式记录一下里面的坑。
参考了下面的文章
同步代码
console.log('script start');
console.log('script end');
这个的输出一看便知:
script start
script end
Promise 的情况
console.log('script start');
new Promise((resolve) => {
console.log('promise1');
resolve();
}).then(function () {
console.log('promise1 then1');
}).then(function () {
console.log('promise1 then2');
});
new Promise((resolve) => {
console.log('promise2');
resolve();
}).then(function () {
console.log('promise2 then1');
}).then(function () {
console.log('promise2 then2');
});
console.log('script end');
关于 Promise 有两个点需要注意:
- Promise 的构造函数是同步执行的,不是在微任务中执行
- Promise 的每个 then 都是在上一个 then 执行之后增加到微任务队列中的
具体到上面的代码,promise1 和 promise2 会在 script end 之前打印,而 promise1 then2 会在 promise2 then1 之后打印。
最终的输出如下:
async/await
console.log("script start");
async function fun1(){
console.log("fun1 start");
await Promise.resolve();
console.log("fun1 end");
}
async function fun2() {
console.log("fun2 start");
await fun3();
console.log("fun2 end");
}
function fun3(){
console.log("fun3");
}
fun1();
fun2();
console.log("script end");
async/await 需要注意的点有两个,一是只要是 await 后面的代码都是会放到微任务里面去执行,不管 await 调用的是同步还是异步的代码,二是 await 调用的代码也是同步执行的,执行到异步的代码才会到宏任务或者微任务。
具体到上面的代码,fun1 end 和 fun2 end 都是在微任务中执行,而 fun3 是在同步任务中。
最终的输出如下:
setTimeout
console.log('script start');
setTimeout(function () {
console.log('setTimeout');
}, 0);
console.log('script end');
只有 setTimeout 的情况时比较好理解的,setTimeout 的代码会在宏任务中执行,即使定时器时 0 也不是立即执行。
上面的代码执行结果:
从上面的输出可以看出宏任务和微任务的差异,之前的微任务执行脚本中输出的 undefined 在最后,而在宏任务中,脚本输出 undefined 在 setTimeout 之前。
混合的情况
题目来自下面的文章,文章中有更加详细关于机制方面的解释: juejin.cn/post/686884…
console.log('script start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
Promise.resolve()
.then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
async function foo() {
await bar()
console.log('async1 end')
}
foo()
async function errorFunc () {
try {
await Promise.reject('error!!!')
} catch(e) {
console.log(e)
}
console.log('async1');
return Promise.resolve('async1 success')
}
errorFunc().then(res => {
console.log(res);
})
function bar() {
console.log('async2 end')
}
console.log('script end');
从头开始分析代码
// 同步1
console.log('script start');
setTimeout(() => {
// 宏任务 1
console.log('setTimeout');
}, 0);
Promise.resolve()
.then(function() {
// 微任务 1 - 1
console.log('promise1');
}).then(function() {
// 微任务 2 - 1
console.log('promise2');
});
async function foo() {
await bar()
// 微任务 1 - 2
console.log('async1 end')
}
foo()
async function errorFunc () {
try {
await Promise.reject('error!!!')
} catch(e) {
// 微任务 1 - 3
console.log(e)
}
// 微任务 1 - 4
console.log('async1');
return Promise.resolve('async1 success')
}
errorFunc().then(res => {
// 微任务 2 - 2
console.log(res);
})
function bar() {
// 同步 2
console.log('async2 end')
}
// 同步 3
console.log('script end');
最终代码的执行结果与分析的结果是一致的: