基础题
console.log(1);
setTimeout(function () {
console.log(2);
}, 0);
Promise.resolve()
.then(function () {
console.log(3);
})
.then(function () {
console.log(4);
});
看完上面的代码,你觉得会打打印出什么呢?答案在下方,我们一起来分析。
setTimeout 设置 0 毫秒,这样为什么会是 Promise 里面的东西先执行呢?原因是 Promise 会进到微任务队列,而 setTimeout 会是在宏任务队列。在一次事件循环中,宏任务一次只提取一个,所以 console.log(1) 后,会先去看微任务队列,不断提取到执行栈中直到微任务队列为空,因此这边会先执行 Promise ,然后才是 setTimeout。
1;
3;
4;
2;
中阶题
console.log("begins");
setTimeout(() => {
console.log("setTimeout 1");
Promise.resolve().then(() => {
console.log("promise 1");
});
}, 0);
new Promise(function (resolve, reject) {
console.log("promise 2");
setTimeout(function () {
console.log("setTimeout 2");
resolve("resolve 1");
}, 0);
}).then((res) => {
console.log("dot then 1");
setTimeout(() => {
console.log(res);
}, 0);
});
在读完上面的代码,你觉得实际执行后,会打印出什么呢?答案如下,让我们一起来分析。
- 代码执行后会依顺序执行程序,所以这时会先打打印出
'begins' - 接着遇到
setTimeout会把它放到宏任务队列;然后遇到new Promise会先执行,打印出'promise 2',然后又遇到一个setTimeout所以把它放到宏任务队列。 - 接着主线程又空了,所以去检查宏任务队列,执行队列中的最先的那个
setTimeout,这时打印出'setTimeout 1',然后遇到Promise.resolve(),把它放到微任务队列。 - 因为宏任务每次只会执行第一个项目,所以这时会去看微任务队列,发现里面有第三步放入的
Promise.resolve()所以打打印出'promise 1'。 - 这时微任务队列空了,所以回去看宏任务队列,里面有个第二步放的
setTimeout,所以打印出'setTimeout 2' - 然后因为这边调用了
resolve所以进入到.then于是打打印出'dot then 1' - 以及再把
setTimeout放到宏任务队列,因为这时微任务队列已经是空的,所以把宏任务队列中的setTimeout放到执行栈,然后执行console.log(res),因为刚刚第六步resolve的值是resolve 1,所以最后打印出resolve 1
"begins";
"promise 2";
"setTimeout 1";
"promise 1";
"setTimeout 2";
"dot then 1";
"resolve 1";
进阶题
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
console.log("script start");
setTimeout(function () {
console.log("setTimeout");
}, 0);
async1();
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("promise2");
});
console.log("script end");
这一题大家觉得会打印出什么呢?跟上一题的差别是这题有 async 的语法。答案在下方,我们一样一行行分析。
- 代码执行后会依顺序执行程序,所以这时会先打印出
'script start',接着把setTimeout把它放到宏任务队列 - 然后调用
async1函数,打印出'async1 start' - 然后调用
await async2()所以打印出'async2'。注意,await后的代码会被放到微任务队列,所以不会马上打印出'async1 end'而是会把它放到微任务队列 - 接着程序继续执行,遇到
new Promise先打印出里面的'promise 1' - 然后调用
resolve,把.then的放到微任务队列。程序继续执行,打打印出'script end' - 这时候执行栈空了,所以去检查微任务队列,先打打印出第三步放的
'async1 end' - 因为微任务队列会一路执行到没东西,所以继续看微任务队列,发现里面还有刚刚第四步骤放入的
resolve代码,所以打打印出'promise2' - 这时微任务队列空了,去看宏任务队列,有第一步放入宏任务队列的
setTimeout所以把它打印出
"script start";
"async1 start";
"async2";
"promise1";
"script end";
"async1 end";
"promise2";
"setTimeout";