阿里一面:熟悉事件循环?那谈谈为什么会分为宏任务和微任务。

WebSocket 的11个面试知识点 WebSocket 作为一种基于 TCP 协议的实时通信协议,为前端应用提供了强大的双向通信能力。本文将深入探讨前端 WebSocket 的相关问题,包括协议区别、用法、关键技术点等。 阅读详情

什么是事件循环

在了解事件循环前,需要一些有关JS特性的前置知识。

JS引擎是单线程的,直白来说就是一个时间点下JS引擎只能去做一件事情,而Java这种多线程语言,可以同时做几件事情。

JS做的任务分为同步和异步两种,所谓 “异步”,简单说就是一个任务不是连续完成的,先执行第一段,等做好了准备,再回过头执行第二段,第二段也被叫做回调;同步则是连贯完成的。

像读取文件、网络请求这种任务属于异步任务:花费时间很长,但中间的操作不需要JS引擎自己完成,它只用等别人准备好了,把数据给他,他再继续执行回调部分。

如果没有特殊处理,JS引擎在执行异步任务时,应该是存在等待的,不去做任何其他事情。用一个图来展示这个过程,可以看出,在执行异步任务时有大量的空闲时间被浪费。

实际上这是大多数多线程语言的处理办法。但对于JS这种单线程语言来说,这种长时间的空闲等待是不可接受的:遇到其他紧急任务,Java可以再开一个线程去处理,JS却只能忙等。

所以采取了以下的“异步任务回调通知”模式:

在等待异步任务准备的同时,JS引擎去执行其他同步任务,等到异步任务准备好了,再去执行回调。这种模式的优势显而易见,完成相同的任务,花费的时间大大减少,这种方式也被叫做非阻塞式。

而实现这个“通知”的,正是事件循环,把异步任务的回调部分交给事件循环,等时机合适交还给JS线程执行。事件循环并不是JavaScript首创的,它是计算机的一种运行机制。

事件循环是由一个队列组成的,异步任务的回调遵循先进先出,在JS引擎空闲时会一轮一轮地被取出,所以被叫做循环。

根据队列中任务的不同,分为宏任务和微任务。

宏任务和微任务

事件循环由宏任务和在执行宏任务期间产生的所有微任务组成。完成当下的宏任务后,会立刻执行所有在此期间入队的微任务。

这种设计是为了给紧急任务一个插队的机会,否则新入队的任务永远被放在队尾。区分了微任务和宏任务后,本轮循环中的微任务实际上就是在插队,这样微任务中所做的状态修改,在下一轮事件循环中也能得到同步。

常见的宏任务有:script(整体代码)/setTimout/setInterval/setImmediate(node 独有)/requestAnimationFrame(浏览器独有)/IO/UI render(浏览器独有)

常见的微任务有:process.nextTick(node 独有)/Promise.then()/Object.observe/MutationObserver

宏任务setTimeout的误区

setTimeout的回调不一定在指定时间后能执行。而是在指定时间后,将回调函数放入事件循环的队列中。

如果时间到了,JS引擎还在执行同步任务,这个回调函数需要等待;如果当前事件循环的队列里还有其他回调,需要等其他回调执行完。

另外,setTimeout 0ms 也不是立刻执行,它有一个默认最小时间,为4ms。

所以下面这段代码的输出结果不一定:

// node
setTimeout(() => {
  console.log('setTimeout')
}, 0)
setImmediate(() => {
  console.log('setImmediate')
})

因为取出第一个宏任务之前在执行全局Script,如果这个时间大于 4ms,这时 setTimeout 的回调函数已经放入队列,就先执行 setTimeout;如果准备时间小于 4ms,就会先执行 setImmediate。

浏览器的事件循环

浏览器的事件循环由一个宏任务队列+多个微任务队列组成。

首先,执行第一个宏任务:全局Script脚本。产生的的宏任务和微任务进入各自的队列中。执行完Script后,把当前的微任务队列清空。完成一次事件循环。

接着再取出一个宏任务,同样把在此期间产生的回调入队。再把当前的微任务队列清空。以此往复。

宏任务队列只有一个,而每一个宏任务都有一个自己的微任务队列,每轮循环都是由一个宏任务+多个微任务组成。

下面的Demo展示了微任务的插队过程:

Promise.resolve().then(()=>{
  console.log('第一个回调函数:微任务1')  
  setTimeout(()=>{
    console.log('第三个回调函数:宏任务2')
  },0)
})
setTimeout(()=>{
  console.log('第二个回调函数:宏任务1')
  Promise.resolve().then(()=>{
    console.log('第四个回调函数:微任务2')   
  })
},0)
// 第一个回调函数:微任务1
// 第二个回调函数:宏任务1
// 第四个回调函数:微任务2
// 第三个回调函数:宏任务2

打印的结果不是从1到4,而是先执行第四个回调函数,再执行第三个,因为它是一个微任务,比第三个回调函数有更高优先级。

Node 的事件循环

node的事件循环比浏览器复杂很多。由6个宏任务队列+6个微任务队列组成。

宏任务按照优先级从高到低依次是:

其执行规律是:在一个宏任务队列全部执行完毕后,去清空一次微任务队列,然后到下一个等级的宏任务队列,以此往复。一个宏任务队列搭配一个微任务队列。

六个等级的宏任务全部执行完成,才是一轮循环。

其中需要关注的是:Timers、Poll、Check阶段,因为我们所写的代码大多属于这三个阶段。

  1. Timers:定时器setTimeout/setInterval;
  2. Poll :获取新的 I/O 事件, 例如操作读取文件等;
  3. Check:setImmediate回调函数在这里执行;

除此之外,node端微任务也有优先级先后:

  1. process.nextTick;
  2. promise.then 等;

清空微任务队列时,会先执行process.nextTick,然后才是微任务队列中的其他。

下面这段代码可以佐证浏览器和node的差异:

console.log('Script开始')
setTimeout(() => {
  console.log('第一个回调函数,宏任务1')
  Promise.resolve().then(function() {
    console.log('第四个回调函数,微任务2')
  })
}, 0)
setTimeout(() => {
  console.log('第二个回调函数,宏任务2')
  Promise.resolve().then(function() {
    console.log('第五个回调函数,微任务3')
  })
}, 0)
Promise.resolve().then(function() {
  console.log('第三个回调函数,微任务1')
})
console.log('Script结束')
node端:
Script开始
Script结束
第三个回调函数,微任务1
第一个回调函数,宏任务1
第二个回调函数,宏任务2
第四个回调函数,微任务2
第五个回调函数,微任务3

浏览器
Script开始
Script结束
第三个回调函数,微任务1
第一个回调函数,宏任务1
第四个回调函数,微任务2
第二个回调函数,宏任务2
第五个回调函数,微任务3

可以看出,在node端要等当前等级的所有宏任务完成,才能轮到微任务:第四个回调函数,微任务2在两个setTimeout完成后才打印。

因为浏览器执行时是一个宏任务+一个微任务队列,而node是一整个宏任务队列+一个微任务队列。

node11.x 前后版本差异

node11.x 之前,其事件循环的规则就如上文所述:先取出完一整个宏任务队列中全部任务,然后执行一个微任务队列。

但在11.x 之后,node端的事件循环变得和浏览器类似:先执行一个宏任务,然后是一个微任务队列。但依然保留了宏任务队列和微任务队列的优先级。

可以用下面的Demo佐证:

console.log('Script开始')
setTimeout(() => {
  console.log('宏任务1(setTimeout)')
  Promise.resolve().then(() => {
    console.log('微任务promise2')
  })
}, 0)
setImmediate(() => {
  console.log('宏任务2')
})
setTimeout(() => {
  console.log('宏任务3(setTimeout)')
}, 0)
console.log('Script结束')
Promise.resolve().then(() => {
  console.log('微任务promise1')
})
process.nextTick(() => {
  console.log('微任务nextTick')
})

在 node11.x 之前运行:

Script开始
Script结束
微任务nextTick
微任务promise1
宏任务1(setTimeout)
宏任务3(setTimeout)
微任务promise2
宏任务2(setImmediate)

在 node11.x 之后运行:

Script开始
Script结束
微任务nextTick
微任务promise1
宏任务1(setTimeout)
微任务promise2
宏任务3(setTimeout)
宏任务2(setImmediate)

可以发现,在不同的node环境下:

  1. 微任务队列中process.nextTick都有更高优先级,即使它后进入微任务队列,也会先打印微任务nextTick微任务promise1;
  2. 宏任务setTimeout比setImmediate优先级更高,宏任务2(setImmediate)是三个宏任务中最后打印的;
  3. 在node11.x之前,微任务队列要等当前优先级的所有宏任务先执行完,在两个setTimeout之后才打印微任务promise2;在node11.x之后,微任务队列只用等当前这一个宏任务先执行完。

结语

事件循环中的任务被分为宏任务和微任务,是为了给高优先级任务一个插队的机会:微任务比宏任务有更高优先级。

node端的事件循环比浏览器更复杂,它的宏任务分为六个优先级,微任务分为两个优先级。node端的执行规律是一个宏任务队列搭配一个微任务队列,而浏览器是一个单独的宏任务搭配一个微任务队列。但是在node11之后,node和浏览器的规律趋同。

如果觉得这篇文章对你有帮助,给我点个赞呗~这对我很重要

3D坐标系转换实战:如何用Python快速实现旋转矩阵与平移向量的组合变换 本文详细介绍了如何使用PythonNumPy实现3D坐标系转换中的旋转矩阵与平移向量的组合变换。通过齐次坐标变换矩阵的数学原理,结合代码示例,帮助开发者高效处理机器人路径规划计算机视觉中的空间变换问题,并解决实际应用中的常见错误。 阅读详情

相关推荐

面试率 90% 的JS事件循环Event Loop,看这篇就够了!! !

面试率 90% 的JS事件循环Event Loop,看这篇就够了!! ! 事件循环(Event Loop)大家应该并不陌生,它是前端极其重要的基础知识。在平时的讨论或者面试中也是一个非常高频的话题。 理解 JavaScript事件循环往往伴随着任务任务JavaScript 单线程执行过程及浏览器异步机制等相关问题,而浏览器 NodeJS 中的事件循环实现也是有很大差别。熟悉事件循环,了解浏览器运行机制将对我们理解 JavaScript 的执行过程排查运行问题有很大帮助。 一、浏览器 JS

道阻且长,行则将至。 2万+

JS事件循环(Event Loop)

一、任务树。

xufang461010923的专栏 5757

WebSocket面试常见知识点面试题

WebSocket是一种网络通信协议,提供全双工通信机制,允许服务器主动向客户端发送消息,实现实时双向数据传输。WebSocket的设计理念是为了解决HTTP协议在实时性方面的不足。连接方式:HTTP协议是无状态的,每次通信都需要建立新的连接。而WebSocket在初次握手后,会保持一个持久的连接,用于后续的数据传输,减少了连接建立的开销。实时性:WebSocket提供了更高的实时性,服务器端有新数据时可以立即推送给客户端,而HTTP协议通常需要客户端定期发送请求来获取更新。消息格式。

大模型大数据攻城狮的专栏 7485

JavaScript事件循环机制(EventLoop)

当一个任务中产生了任务,这些任务会先被放到一个专门的队列中,等待当前任务执行完毕时再执行。而在执行这些任务时,如果又产生了新的任务,这些新的任务会被放到队列的末尾,等待执行。当当前任务执行完后,在下一个事件循环的开始,JavaScript会从任务队列中取出一个任务,执行该任务。然后再执行任务队列中的任务。总的来说,JavaScript通过事件循环机制来实现异步操作,将异步任务放到任务队列中,然后在任务队列中等待执行,直到JavaScript引擎空闲,再将任务队列中的任务拿出来执行。

snow的博客 1万+

【面试必备】事件循环(EventLoop)、任务任务

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索长,自己不体系的自学效果低效漫长且无助。因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!

2401_84152177的博客 916

前端面试必考题:JavaScript事件循环(Event loop)、任务任务

所以,这并没有违背回调队列的先进先出原则,一个任务中如果伴随着任务,那么就先执行任务任务先放置,等到后面的任务一个个都执行完后,再开始执行任务!// setTimeout 的回调是 任务2,进入回调队列排队。// setTimeout 的回调是 任务,进入回调队列排队。// Promise 的回调是 任务,本轮调用末尾直接执行。// Promise 的回调是 任务,本轮调用末尾直接执行。对于定长不定长的数据,HTTP 是怎么传输的?HTTP 中如何处理表单数据的提交?

m0_60634964的博客 1222

事件循环任务Node环境浏览器)

setTimeout为什么会比promise里面的迟缓执行?以下代码就说明该问题。/*执行结果:1–2–4–ok3–5–*/执行该结果的原因:第一个console.log(1)是同步任务,直接执行,遇到new Promise内部的console.log(2)是同步任务,直接执行,遇到setTimeout是任务,加入任务的event table中,并注册函数,当时间片执行结束,再将该回调函数加入event queue中,遇到console.log(4)是同步任务,直接执行,

2401_84091502的博客 1156

一起谈一谈js中的任务任务

秋招即将开始,校招的朋友普遍是缺少项目经历的,所以底层逻辑,基础知识要掌握好!而一般的社招,更是神仙打架。特别强调,项目经历不可忽视;几乎简历上提到的项目都会被刨根问底,所以项目应用的技术要熟练,底层原理必须清楚。这里给大家提供一份汇集各大厂面试高频核心考点前端学习资料。涵盖HTML,CSS,JavaScript,HTTP,TCP协议,浏览器,Vue框架,算法等高频考点238道(含答案)!开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】高级前端工程师必备资料包。

2401_83621499的博客 949

js中的任务任务

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索长,自己不体系的自学效果低效漫长且无助。因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!

2401_84097745的博客 933

【面试必备】事件循环(EventLoop)、任务任务,2024年最新研发岗面试题

js执行同步任务异步任务的过程中,在主线程执行栈中的同步任务执行完毕就会,读取任务队列中的回调函数,将回调函数放到主线程执行栈中执行,执行完毕又会继续读取任务队列中的回调函数,放到主线程执行栈中执行,如此往复的过程称为事件循环(EventLoop);在每一个任务执行完毕后就会去查找是否存在任务,如果任务存在就将任务执行完毕再去执行下一个任务,以此往复;以上内容已经讲解了同步任务异步任务的概念,javascript将异步任务又进一步划分任务任务;🥇 三、任务任务的执行顺序。

m0_74931199的博客 825

kafka面试题汇总,js中的任务任务

其他的内容都可以按照路线图里面整理出来的知识点逐一去熟悉,学习,消化,不建议你去看书学习,最好是多看一些视频,把不懂地方反复看,学习了一节视频内容第二天一定要去复习,并总结思维导图,形树状知识网络结构,方便日后复习。这里还有一份很不错的《Java基础核心总结笔记》,特意跟大家分享出来目录:部分内容截图:《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!258)][外链图片转存中…(img-9YYiahzf-1713459653260)]

2401_84415652的博客 1116

一起谈一谈js中的任务任务!(1)

面试一面会问很多基础问题,而这些基础问题基本上在网上搜索,面试题都会很多很多。最好把准备一下常见的面试问题,毕竟面试也相当与一次考试,所以找工作面试的准备千万别偷懒。面试就跟考试一样的,时间长了不复习,现场表现肯定不会太好。表现的不好面试官不可能说,我猜他没发挥好,我录用他吧。开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】96道前端面试题:常用算法面试题:内容主要包括HTML,CSS,JavaScript,浏览器,性能优化太好。

2401_83621384的博客 1013

前端面试必考题:JavaScript事件循环(Event loop)、任务任务(2)

总的来说,面试官要是考察思路就会从你实际做过的项目入手,考察你实际编码能力,就会让你在电脑敲代码,看你用什么编辑器、插件、编码习惯等。所以我们在回答面试官问题时,有一个清晰的逻辑思路,清楚知道自己在面试官说项目说技术时的话就好了网上学习资料一大堆,但如果学到的知识不体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)一个人可以走的很快,但一群人才能走的更远!

m0_60634964的博客 769

js中的任务任务

2020年在匆匆忙忙慌慌乱乱中就这么度过了,我们迎来了新一年,互联网的发展如此之快,技术日新月异,更新迭代为了这个时代的代名词,坚持下来的技术体系会越来越健壮,JVM作为如今是跳槽大厂必备的技能,如果你还没掌握,更别提之后更新的新技术了。更多JVM面试整理:《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!外链图片转存中…(img-ygHuEK8w-1713208101197)]

2401_84048832的博客 686

任务任务的总结(js队列执行顺序)+ 一点琐事(善待自己)

本周日内容是:任务任务的总结(js队列执行顺序)+ 一点琐事(善待自己) 前言 之后每次文章都计划是 一点知识点 +生活中一点琐事(我也想做个技术博主,但是能力不足,只能再添加一些生活琐事了)。再次提前声明,如果文章有技术性错误、错别字、或者语义错误的句子,希望您提一下,非常感谢。 js执行队列 任务 任务:进入一个js文件,js文件中所有的代码就可以看作为任务任务是一个执行队列,它中间还可以再包括任务任务,但是在执行时候,会“挂起”一些后执行的任务任务。 包括:刚刚进入js.

DoLi_JIN的博客 1248

事件循环任务Node环境浏览器)(1)

)})/*执行顺序:12435*/解释结果顺序:执行同步任务,1输出,setTimeout加入任务的event table中,并注册函数,等时间片结束后进入任务的event queue,此时同步任务执行完毕,且没有任务,执行任务的event queue,

weixin_58085973的博客 842

美团一面阿里一面复盘总结

这两面的面试官风格截然不同,美团一面主要想看我基础知识到底扎不扎实,并不会继续进行深层次的追问,觉得我原理掌握的差不多就直接跳到另一个问题。而阿里一面给我的感觉就是思路很跳脱,面试官会不断根据我说的追问下去,而且问题往往不是那种标准的问法。 相对而言,我美团一面表现的还不错,问题基本都答上来了,而且做了很多延伸,很多时候都是面试官打断我说可以了。而阿里面试官不会听我太多bb(hh,因为我回答问题都是根据我自己的理解然后用口语化的表达出来的,所以能讲很长时间

风过孤屿,山海自成诗行。 2万+

整理 钢琴 约翰汤普森-简易钢琴(小汤)

文件名:(小汤1)约翰-汤普森钢琴1 超清PDF (原版引进)文件名:(小汤2)约翰-汤普森钢琴2 超清PDF (原版引进)文件名:(小汤3)约翰-汤普森钢琴3 超清PDF (原版引进)文件名:(小汤4)约翰-汤普森钢琴4 超清PDF (原版引进)文件名:(小汤5)约翰-汤普森钢琴5 超清PDF (原版引进)文件大小:20.1 MB。文件大小:23.7 MB。文件大小:45.7 MB。文件大小:51.7 MB。文件大小:72.0 MB。

TS的博客 4万+

基于STM32的交通灯控制系统仿真+keil代码+参考报告

基于STM32的交通灯控制系统proteus仿真+keil代码+参考报告

上一篇: 穷追猛打,阿里二面问了我30分钟从URL输入到渲染...
下一篇: 阿里三面:灵魂拷问——有react fiber,为什么不需要vue fiber呢?
前端私教年年
博客等级 码龄4年 8粉丝 6原创
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值