面试官:聊一下 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,欢迎大家学习指正!

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

相关推荐
庸俗今天不摸鱼2 分钟前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX187302 分钟前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下9 分钟前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox19 分钟前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞22 分钟前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行22 分钟前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_5937581023 分钟前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox
掘金一周26 分钟前
金石焕新程 >> 瓜分万元现金大奖征文活动即将回归 | 掘金一周 4.3
前端·人工智能·后端
三翼鸟数字化技术团队44 分钟前
Vue自定义指令最佳实践教程
前端·vue.js
uhakadotcom1 小时前
构建高效自动翻译工作流:技术与实践
后端·面试·github