代码如下
async function async1 () {
console.log('async1--start');
await async2();
console.log('async1--end')
}
async function async2 () {
console.log('async2--')
}
console.log('script--start')
setTimeout (() => {
console.log('setTimeout')
},0)
async1()
new Promise ((resovle,reject) => {
console.log('promise--1');
resovle()
}).then(() => {
console.log('promise--2')
}).catch(() => {
console.log('promise--reject')
})
console.log('script--end')
浅分析
1.根据js代码从上往下执行原理,首先函数定义时不执行,所以最先执行的是console.log('script--start'),所以第一个先打印的是'script--start'
2.接下来代码执行到setTimeout,此时setTimeout作为异步且为宏任务,丢入异步队列中,继续往下走,此时调用async1(),函数被调用时,会立马执行函数体,所以此时执行console.log('async1--start'),所以第二个打印的是'async1--start'
3.再接下来到 await async2(),此时会立即执行函数体async2(),所以第三个打印'async2--',此时await async2()后面的代码全部做异步处理,作为微任务丢入异步队列
4. 继续往下走执行new Promise()代码,promise传入的函数体会立即执行,所以第四个打印的是'promise--1',然后调用resovle(),此时promise的状态是fulfilled,所以会进入.then()并不会进入.catch(),所以.catch()里面的代码不会执行,由于.then()是异步代码切是微任务,丢进异步队列
5.继续往下走执行console.log('script--end'),所以地五个打印的是'script--end',同步代码执行完毕
6.执行异步代码,先执行微任务再执行宏任务,第3步异步队列丢进去的微任务先执行,所以第六个打印的是'async1--end',再执行第4步丢进去的微任务.then(),第七个打印的是'promise--2',最后微任务执行完毕,执行宏任务setTimeout,第八个打印的是'setTimeout'
所以最终的打印顺序是:
'script--start'
'async1--start'
'async2--'
'promise--1'
'script--end'
'async1--end'
'promise--2'
'setTimeout'
总结
由于js是单线程,所以先执行同步代码再执行异步代码,由于event loop机制,微任务是在DOM渲染前触发,宏任务是在DOM渲染后触发,所以异步代码中先执行微任务(.then(),async/await)(ES6规范) 再执行宏任务(setTimeout,setInterval,Ajax,DOM事件)(W3C规范)