async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
console.log("js start");
setTimeout(function () {
console.log("timeout");
}, 0);
async1();
new Promise(function (resolve) {
console.log("promise");
resolve();
}).then(function () {
console.log("then");
});
console.log("js end");
话不多说,先上结果
// 控制台输出结果
"js start"
"async1 start"
"async2"
"promise"
"js end"
"async1 end"
"then"
"timeout"
宏任务 微任务
如果看官是个新手的话,看到上面的输出结果,肯定一脸懵逼的,但是没关系,看完这篇文章您就懂了。想完全明白上面这道题目,还需要了解JS的两个概念,没错,就是宏任务和微任务。
首先看官肯定知道JS是单线程,实现异步的方法就是定时器和es6+出现的promise/async等,那么现在问题来了,既然es6出现的新的异步方式,那么和之前的定时器相比,那个异步先执行呢?
宏任务
(macro)task,可以理解为每段代码都是一个宏任务,没错JS的主程序也是宏任务。同时两个定时器异步的部分也是宏任务。
微任务
microtask,可以理解是在当前 task 执行结束后立即执行的任务。也就是在主程序执行完成之后立即执行的部分。es6+出现的promise,async都是微任务。在这里要记住一句话,微任务的优先级是高于宏任务的。
程序执行顺序
1、主程序
因为js是单线程的,同一时间只能有一段代码在执行,所以首先执行的就是JS的主程序。之前说主程序是宏任务,微任务优先级又比宏任务高,那为什么还先执行主程序这个宏任务呢?
这是因为:没有主程序去构建微任务,微任务又怎么会出现呢,没有微任务的出现,当然就去找到主程序这个宏任务了,所以优先级的说法没有错误。
2、检查是否有异步任务
当上一个任务执行完成之后,程序会去检索是否有微任务,需要执行,如果有,就会先执行微任务。没有微任务但有宏任务,执行宏任务。没有任务,代码不在执行。
3、微任务
微任务代码执行,和正常的JS代码执行没有区别,从上往下编译执行!!!执行完成之后,会跳回到第二步。
4、宏任务
宏任务代码执行,和正常的JS代码执行没有区别,从上往下编译执行!!!执行完成之后,会跳回到第二步。
解答题目
1、主程序 - async async1
程序声明异步async异步函数 async1,当一个函数未调用时,函数内容的代码是不会编译执行的,所以第一步并没有输出内容。
微任务:空
宏任务:空
2、主程序 - async async2
这里同样也只是定义async函数async2, 所以这一步也没有输出内容
微任务:空
宏任务:空
3、主程序 - console.log
程序执行到了console.log,不存在异步,所以直接执行,控制台输出 “js start”。
微任务:空
宏任务:空
4、主程序 - setTimeout
程序终于来到了第一个异步部分setTimeout,这个单次定时器的定时为0s,意思为立即执行,但是因为他是异步的,所以他并不会立即执行,而是等到所有的主程序和排在他之前的异步任务执行完成之后才会执行。这里会把他添加到宏任务队列。
微任务:空
宏任务:setTimeout
5、主程序 - async1()
程序执行到了async1的函数调用,不存在异步,所以程序会去编译并执行async1内部部分。
微任务:空
宏任务:setTimeout
5.1、async1 - console.log
async异步函数是这样的,函数被调用时,程序会正常立即执行,但是当碰到await关键词时,await下一行的语句会作为微任务加入到微任务队列中,await后面跟着的部分也是会立即执行的。因此这个console.log会立即执行,控制台输出“async1 start”
微任务:空
宏任务:setTimeout
5.2、async1 - await async2()
await语句后面的内容会立即执行,下一行和之后的内容会加入到微任务队列,所以又进入到async2里面,并在微任务队列加入一个微任务。
微任务:async1
宏任务:setTimeout
5.2.1、async2 - console.log
console.log 是立即执行的,没有异步部分,所以控制台上输出“async2”。至此,async1里面的同步内容执行完成了。
微任务:async1
宏任务:setTimeout
6、主程序 - Promise
promise的异步是这样的,在构建实例时传入函数的内容,是立即编译执行的,后面的then会加入到微任务队列。
微任务:async1
宏任务:setTimeout
6.1、Promise - console.log
console.log立即执行,没有异步部分。控制台输出“primise”。
微任务:async1
宏任务:setTimeout
6.2、Promise - resolve
resolve立即执行,但是后面的then加入微任务队列。
微任务:async1 Promise-then
宏任务:setTimeout
7、主程序 - console.log
console.log立即执行,没有异步部分。控制台输出“js end”。至此,主程序已经执行完成,接下来会执行上述的第二步。
微任务:async1 Promise-then
宏任务:setTimeout
8、微任务 async1 - console.log
监测到有微任务,执行微任务。console.log立即执行,没有异步部分。控制台输出“async1 end”。同时删除微任务队列中对应的任务,再次回到第二步。
微任务:Promise-then
宏任务:setTimeout
9、微任务 Promise-then - console.log
监测到有微任务,执行微任务。console.log立即执行,没有异步部分。控制台输出“then”。同时删除微任务队列中对应的任务,再次回到第二步。
微任务:空
宏任务:setTimeout
10、宏任务 setTimeout - console.log
监测到没有微任务,执行宏任务队列。console.log立即执行,没有异步部分。控制台输出“timeout”。同时删除宏任务队列中对应的任务,再次回到第二步。
微任务:空
宏任务:空
11、执行结束
检测到任务队列都已执行完成,代码执行结束。
总结
至此、面试题就已经讲解完成了,内容比较长,但是也比较细,各位碰到类似题目时,可以按照我的方法去做一下,基本不会再出错了。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!