浅谈JS执行顺序
async function f() {
setTimeout(()=>{
return 1
},1000)
}
async function aaa(){
const bbb = await f()
console.log('bbb',bbb);
}
aaa()
今天在学async、await的时候写了上面那个代码,输出结果竟然是undefined,搜了好多资料发现是执行顺序的原因。下面谈谈今天我学到的东西
JS EventLoop 事件循环
因为JS有同步任务和异步任务,异步任务又分为**宏任务(macrotask)和微任务( microtask )**两种
我将JS代码执行分为3块部分:执行队列、宏任务队列、微任务队列
JS代码执行时先将所有代码放到执行队列,在执行队列中碰到宏任务时,将之放到宏任务队列等候,遇到微任务时放到微任务队列等候,执行队列的代码执行完毕时检查微任务队列,有则放到执行队列,无则检查宏任务队列,有宏任务则放到执行队列
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');
//打印结果如下
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
这是一道经典题目了,这边先来分析一下
首先将所有代码放到执行队列,打印**‘script start’**
碰到setTimeout,将**‘setTimeout’**放到宏任务队列等待(压入宏任务栈中计时器会开启,不会等待执行队列结束后开启,但是其中代码不会执行)
然后调用async1()打印’async1 start’,在async1里碰到了await async2(),调用打印**‘async2’,然后将’async1 end’**放到微任务队列等待
await async2()
console.log('async1 end')
等价为
Promise.resolve(async2()).then(() => {
console.log('async1 end')
})
继续执行new Promise,打印**‘promise1’,因为then将’promise2’**放到微任务队列
然后打印**‘script end’**
此时执行队列中没有代码了,检查微任务队列,按照先后顺序打印**‘async1 end’和’promise2’**
微任务队列执行完毕后检查宏任务队列,打印**‘setTimeout’**后全部执行
所以在我的代码中,bbb并不为1,而是f()没有返回值为undefinded,而setTimeout里的return是其自身的返回值
变化
async function async1() {
console.log('async1 start');
await async2();
//更改如下:
setTimeout(function() {
console.log('setTimeout1')
},0)
}
async function async2() {
//更改如下:
setTimeout(function() {
console.log('setTimeout2')
},0)
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout3');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
//打印结果:
script start
async1 start
promise1
script end
promise2
setTimeout3
setTimeout2
setTimeout1
此处**await async2()之后的’setTimeout1’**被一起带到了宏任务队列中
一次修改 22/1/17
二次修改 22/1/25
参考: https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/7