Event Loop:都给我乖乖站好排队
作者:cc的牛奶ovo
疑惑
为什么会要有Event Loop这种执行机制?仅依靠同步执行代码不能够完成执行任务吗?
接下来用一个例子展示出它存在于代码执行机制中的必要性:
<script>
console.log(1111);
// 宏任务
setTimeout(()=>{
console.log('1234');
},3000)
console.log("22222");
// 宏任务
setTimeout(()=>{
console.log('5678');
},5000)
</script>
由于js是一种单线程语言,任何给定时刻只能执行一个任务
由此理解,这段代码的输出会是按顺序输出吗?如果是以同步代码同步执行的理解,输出顺序会是
1111
1234
22222
5678
但是如果这样的话,宏任务的出现会使后续代码阻塞。
为什么会需要Event Loop
但是如果在真正的项目中,也是以同步执行的机制,所有的代码都要等待前面代码执行完之后才能执行时,程序的灵活性和效率将会大大降低,因为项目中经常会有一些宏任务(异步任务的一种),也就是需要一定时间才能够完成的任务,在同步执行的机制下,所有代码需要等待前方的宏任务执行完毕,这样会造成代码的阻塞,大大降低程序执行的效率和用户的体验。所以为了解决这个问题,Event Loop机制横空出世,以上代码在Event Loop的执行机制下,输出顺序会是:
1111
22222
1234
5678
原因
是因为在js的event loop执行机制中,会首先执行同步代码console.log(1111),在执行之后准备执行setTimeout(()=>{ console.log(‘1234’); },3000)这段代码时,v8检测到这段代码是宏任务,也就是需要一些时间去处理,所以它不会立即执行回调函数,而是将一个定时器事件在事件队列中注册,三秒后再将回调函数从事件队列中取出在执行栈中执行,下面的setTimeout(()=>{ console.log(‘5678’); },5000)此代码也是同理。
Event Loop底层过程
事件循环主要由以下几个部分组成:
调用堆栈(Call Stack) :这是一个后进先出的数据结构,用于存储正在执行的函数。每当一个新的函数被调用时,它就会被压入调用堆栈;当函数执行完毕,它就会从调用堆栈中弹出。
2.消息队列(Message Queue) :这是一个先进先出的数据结构,用于存储待处理的异步回调函数。每当一个异步操作完成时,相应的回调函数就会被放入消息队列。
3.事件循环(Event Loop) :这是整个机制的心脏,它不断地检查调用堆栈和消息队列。当调用堆栈为空时,事件循环会从消息队列中取出一个任务,将其压入调用堆栈,开始执行。
工作流程
1.执行同步代码:JavaScript引擎执行代码中的同步部分,将每个函数压入调用堆栈,执行完毕后弹出。
2.处理异步操作:遇到异步操作(如setTimeout、fetch、setInterval等)时,JavaScript引擎不会等待这些操作完成,而是立即返回控制权给调用堆栈顶部的函数,同时将异步操作的回调函数放入事件队列中等待。
3.事件循环检查:当调用堆栈为空时,事件循环会检查消息队列。如果消息队列中有任务,它会取出队列中的第一个任务,压入调用堆栈执行。
4.重复上述过程:事件循环会持续检查调用堆栈和消息队列,直到消息队列为空且没有更多的异步操作待处理。
小结
总的来说,在传统的同步编程中,程序会按顺序执行每一行代码,直到所有任务完成。但在异步编程中,某些任务可能需要等待(例如,从网络请求数据),而程序不应该在这期间停止运行。这就需要用到Event Loop,通过这种方式允许程序在等待某些操作的同时继续执行其他任务,从而实现非阻塞和高效的资源利用。在JavaScript中,这种机制使得即使在处理耗时的I/O操作时,Web应用程序也能保持响应性。
……………………
顺便吆喝一声,技术大厂,内推捞人,前/后端or测试←感兴趣
要求学历:全日制统招本科
—加班偶尔较多,但周末加班两倍工资。
—15-35K,工资在一线城市属于一般,但二线城市很可以。
……………………
- 点赞
- 收藏
- 关注作者
评论(0)