JS面试题详解之JS的执行输出是怎样
Admin 2022-09-13 群英技术资讯 1027 次浏览
这篇文章主要介绍了“JS面试题详解之JS的执行输出是怎样”相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JS面试题详解之JS的执行输出是怎样文章都会有所收获,下面我们一起来看看吧。首先我们来看一道题目,如下javascript代码,执行后会在控制台打印出什么内容?
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2 start');
return new Promise((resolve, reject) => {
resolve();
console.log('async2 promise');
})
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
}).then(function() {
console.log('promise3');
});
console.log('script end')
说实话,真正能在面试中把这道题目答对的前端工程师凤毛麟角。我们先来瞧一下答案吧。把以上代码存到test.js文件中,并用node执行一下,结果如下:

如果把以上代码贴到一个网页中的script标签里面,然后打开这个网页,再打开控制台,可以看到如下输出(Chrome 64位 63.0.3239.84):

结果和node打印的一模一样。那么为什么是这个顺序呢?
我们都知道js的单线程特性(html5的web worker不算在内~)以及良好的异步支持。在单线程的前提下,异步任务到底什么时候开始执行,其实是有两个队列来进行管理,即Macrotask和Microtask(只有一个字母的差距,不要认错……)。在当前正在执行的线程中,如果碰到属于Macrotask的异步任务,则放入Macrotask队列;碰到Microtask的异步任务则放入Microtask队列。注意这里只是把任务放入队列,并不会执行它。等到当前主线程任务执行完毕之后,会依次从Microtask队列中取出任务执行,在执行期间当然还是遵循碰到异步任务放入相应队列的原则。等到Microtask任务全部执行过了,此时再从Macrotask队列中取出一个任务执行。
属于Macrotask的任务有:
setTimeout,setInteveral,script标签,I/O,UI渲染
属于Microtask的任务有:
Promise,async/await,process.nextTick,Object.observe,MutationObserver
(事实上,即使同样是Microtask,内部也是有优先级的差别的,例如NodeJS的实现上,process.nextTick比Promise要先执行。相关问题可以瞧瞧这个连接:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/ 。反正我瞧到一半就放弃了,好在async/await和Promise没有优先级差别)
然后我们来分析一下本题中的执行顺序:
【1】第15行执行,打印出script start
【2】第16至18行,把回调任务放入Macrotask (目前Macrotask:第16行setTimeout,Microtask:空)
【3】第20行,执行async1函数,先打印出第2行的async1 start
【4】第3行的async2先执行,打印出第8行的async2 start
【5】第9行至第12行遇到Promise,先打印出第11行的async2 promise(注意不管你resolve写在new Promise的函数什么位置,都跟写到最后一句一样!)
【6】第3行的async2返回了Promise,并且async2前面有await修饰,因此后面第4行的任务被放到Microtask(目前Macrotask:第16行setTimeout,Microtask:第4行)
【7】第22至25行,打印出promise1,并把第26行放入Microtask,注意第28行还没执行到,所以这行什么都不做(目前Macrotask:第16行setTimeout,Microtask:第4行,第26行)
【8】第30行打印script end(目前Macrotask:第16行setTimeout,Microtask:第4行,第26行)
【9】脚本主线程执行结束,现在拿出来一个Microtask,即第4行,打印async1 end(目前Macrotask:第16行setTimeout,Microtask:第26行)
【10】再拿出来一个Microtask,即第26行,打印promise2,此时由于第26行后面跟着then,所以把第28行插入Microtask(目前Macrotask:第16行setTimeout,Microtask:第28行)
【11】再拿出来一个Microtask,即第28行,打印promise3(目前Macrotask:第16行的setTimeout,Microtask:空)
【12】Microtask没有了,执行下一个Macrotask,即第16行的setTimeout,打印setTimeout,结束
需要注意的是,以下两种写法,效果是一模一样的(resolve的位置无所谓):
写法1:
new Promise((resolve, reject) => {
console.log('1111');
resolve();
console.log('2222');
});
写法2:
new Promise((resolve, reject) => {
console.log('1111');
console.log('2222');
resolve();
});
另外,对于Promise的链式调用,如new Promise(....).then(...).then(...)....,一次只放第一个then的内容进入Microtask,等第一个then执行的时候,会把第二个then放入Microtask,而不是一次把两个then都放进去。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章主要为大家详细介绍了JavaScript如何通过面向对象实现一个简单的扑克牌游戏,文中的示例代码代码讲解详细,感兴趣的可以学习一下
目录根据条件判断按钮是否可以点击方法一:使用v-if 、v-else 来判断方法二:增加一个变量,判断vue判断点击当前元素需要判断你是点击了遮罩层还是form表单接下来是分别对e.currentTarget、e.target打印根据条件判断按钮是否可以点击按钮当在特定环境下不可点击,需要根据判断来控制点击事件。方法一
ajax和websocket有哪些不同?对于ajax和websocket的区别,一些朋友比较好奇,其中两者在本质、生命周期、适用范围、发起人和用法这五方面都有区别,接下来我们详细的了解看看。
这篇文章给大家分享的是隐藏域的作用和获取隐藏域中的值的方法,文中的获取隐藏域中的值的示例是使用jQuery实现的,下文有详细的介绍,有需要的朋友可以参考,接下来就跟随小编来一起学习一下吧!
这篇文章给大家分享的是用JavaScript实现颜色查看器的内容,实现效果如下,通过颜色查看器我们可以预览到这个颜色是不是我们所需的颜色,小编觉得挺实用的,因此分享给大家做个参考,接下来一起跟随小编看看吧。
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 ICP核准(ICP备案)粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008