面试官:聊一下 Event - Loop

在面试中,被问及关于 JS 的 Event Loop 是相当常见的情况。理解 Event Loop 不仅是展示对 异步编程核心原理的理解,同时也展示了对浏览器环境下代码执行机制的掌握程度。

本文将深入浅出地探讨 Event Loop 的引入、概念及执行过程。

什么是 Event Loop?

Event Loop,即事件循环,是 JavaScript 异步编程的核心机制。它是一个持续运行的进程,负责监听执行栈和消息队列(任务队列),确保代码的执行顺序和异步任务的准确执行。

通俗来讲,它就是一个规则,代码会按照这个规则执行下去,不至于被某个需要等待的任务阻塞。

为什么会担心任务阻塞 ?

JS 设计之初是为了实现与用户动态交互的网页,为了能有更好的用户体验,不需占用太多资源,让交互更流畅,从而设计成了单线程

这样的设计简化了编程模型,减少了许多复杂的并发问题,但也引入了一个潜在的问题:同步任务执行时间过长可能导致任务阻塞

如何避免任务阻塞

为了解决任务阻塞的问题,JS 引入了 异步任务事件循环机制 。异步任务通常包括定时器、事件监听器等。当遇到异步任务时,它会被放入任务队列中,而不会立即执行。主线程在执行完当前的同步任务后,会检查任务队列,将等待执行的异步任务取出来执行。

异步任务

想象一下你在餐馆点餐。如果你点了一个需要等待一段时间才能做好的菜,而你不想傻坐在那里等,你可能会继续看菜单,聊天,或者做其他事情。当你点的菜做好了,服务员会把它端到你的桌子上。在这个等待的过程中,你并不需要一直盯着厨房等待,可以去做其他的事情,等待结束后再回来处理这个菜。

在编程中,异步任务就是这样的一个概念。当你执行一个异步任务时,不需要等待它完成,而是继续执行后面的代码。当异步任务完成时,系统会通知你,然后你可以处理它的结果。这样可以充分利用时间,不让程序在等待某些操作的同时停滞不前。

异步任务又分为 宏任务(macrotask)微任务(microtask),它们分别代表着不同的异步执行上下文。

1. 宏任务

常见的宏任务有:

  • script 代码
  • setTimeout
  • setInterval
  • I/O 操作
  • UI 渲染
  • ······

2. 微任务

常见的微任务有:

  • Promise.then() 注:Promise本身是同步任务
  • Async/await
  • MutationObserver 监听DOM变化
  • process.nextTick
  • ······

事件循环的执行顺序

  1. 当JS引擎拿到要执行的代码时,就算进入第一次事件循环,开始执行同步代码(这属于宏任务,因为script内的代码都属于宏任务),同步代码被推入执行栈,并执行;
  2. 当执行栈为空,查看微任务队列中是否有待执行的任务;
  3. 如果微任务队列中有任务,将微任务从队列中取出,推入执行栈,开始执行;
  4. 如果有需要,会渲染页面;
  5. 查看宏任务队列,推入执行栈,执行宏任务,开始下一轮事件循环。

举个栗子🌰

下面代码的打印顺序是怎样的呢?

js 复制代码
console.log('start');
setTimeout(()=>{
    console.log('setTimeout');
    setTimeout(()=>{
        console.log('inner');
    })
    console.log('end');
},1000)
new Promise((resolve,reject)=>{
    console.log('Promise');
    resolve()
}).then(()=>{
    console.log('then1');
}).then(()=>{
    console.log('then2');
})

【答案】(点击展开) start

Promise

then1

then2

setTimeout

end

inner

首先我们对各任务进行划分:

进入第一次事件循环,开始执行同步任务,这时候start和Promise的打印分别进栈并打印,随后出栈,宏任务进入宏任务队列,微任务进入微任务队列。

同步任务执行完后,栈为空,将微任务队列的任务依次推入执行栈执行,分别打印then1,then2。

微任务执行完毕,将宏任务推入执行栈执行,也算第二次事件循环的开始。

第二次事件循环开始,重复上述步骤,同步任务先执行,分别打印setTimeout和end。

微任务队列为空,直接执行宏任务,开始第三次事件循环,打印同步任务console.log('inner')。

所以最终打印结果为:

start

Promise

then1

then2

setTimeout

end

inner

结语

在面试中,对 Event-Loop 的理解也成为评估一个开发者JS能力的重要标准,充分展示了个人对异步编程核心原理的理解。希望这篇文章能够帮助你更好地理解和运用JS的事件循环机制。

最后

看到这里你已经能够准确回答面试官的问题了,那么在后面的文章中,我会针对事件循环机制,再出一期面试题相关的内容,如果你对此感兴趣,可以关注我后面的文章!

已将学习代码上传至github,欢迎大家学习指正!

技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 "点赞 收藏+关注" ,感谢支持!!

相关推荐
_Lok2 分钟前
深入解析 Vue 中 Object.freeze() 的性能优化与实现原理
前端
阿古达木2 分钟前
我在团队内部提倡禁用单元测试
前端·单元测试
光影少年3 分钟前
react中NavLink和a标签区别
react.js·面试
水煮白菜王5 分钟前
如何用HTML5 Canvas实现电子签名功能✍️
前端·javascript·html·html5·canva可画
博主逸尘6 分钟前
uniApp实战二:仿今日相机水印功能
javascript·数码相机·uni-app
黑暗也有阳光6 分钟前
springboot利用Redisson 实现缓存与数据库双写不一致问题
spring boot·redis·面试
lqstyle7 分钟前
面试必备之redis过期策略和内存淘汰策略
后端·面试
硅谷神农7 分钟前
分库分表:数据爆炸时的计划生育政策
面试
lfl183261621608 分钟前
thingsboard edge 在windows 环境下的配置
前端·edge
硅谷神农13 分钟前
翻车案例:用Explain解读慢查询的死亡密码
面试