先看面试题
async function async1(){
console.log('1')
await async2()
console.log('2')
}
async function async2(){
console.log('3')
}
console.log('4')
setTimeout(function(){
console.log('5')
},0)
async1();
new Promise(function(resolve){
console.log('6')
resolve();
}).then(function(){
console.log('7')
})
console.log('8')
上面的题,答案是什么呢?
答案是:4,1,3,6,8,2,7,5
懵逼了吗?反正我第一次接触看到这个面试时候是一脸懵,好吧,继续说。
javascript是单线程,所以只有唯一的事件循环,这个时候js就把所有任务分为了两种:同步任务和异步任务。
而异步任务的两种分类分别为:宏任务和微任务。
同步任务:就是在主线程上排队执行的任务,只有在前面的任务执行完后,才能执行后面的任务;
异步任务:是指不进入主线程,而是进入“任务队列”的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
事件循环EventLoop:
是JS的执行机制,是指同步任务进入主线程后,而异步任务进入Event Table注册函数,当异步事件完成后,会将回调函数放入Event Queue中,当同步任务完成后,会从Event Queue中读取事件放入主线程执行,这个过程不断循环执行。
事件的执行顺序是先执行宏任务,然后执行微任务。微任务按先进先出的顺序执行;微任务清空后再执行宏任务,按先进先出的顺序取出执行。
如下图:
image.png
image.png
宏任务:包括整体代码script,setTimeout,setInterval
微任务:Promise.then(非new Promise),process.nextTick(node中)
下面我们就来看一下上面的结果是怎么得出来的吧!
1.先打印4,这个就不说了;
2.走到setTimeout,是一个宏任务,它要先等当前的宏任务结束后再执行;
3.async1();执行该函数,先打印1,然后执行async2()函数,打印3,因为async2函数前面有await关键字,会隐式返回promise微任务,进入回调队列;
4.执行new promise,同步任务,先打印6,后面.then()微任务进入回调队列;
5.打印8,此时同步任务执行完毕,读取任务队列,进入主线程执行;
6.还记得微任务先进先出的顺序吧,此时先执行async2返回的一个promise,打印2;
7.接着到promise.then(),打印出7;
8.到这里当前的宏任务结束,执行下一轮的宏任务setTimeout,所以最后打印出5;
最终结果就是4.1.3.6.8.2.7.5
再说一下函数前面多了一个aync关键字。
await关键字只能用在aync定义的函数内,async函数会隐式地返回一个promise。
网友评论