在面试中,被问及关于 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
- ······
事件循环的执行顺序
- 当JS引擎拿到要执行的代码时,就算进入第一次事件循环,开始执行同步代码(这属于宏任务,因为script内的代码都属于宏任务),同步代码被推入执行栈,并执行;
- 当执行栈为空,查看微任务队列中是否有待执行的任务;
- 如果微任务队列中有任务,将微任务从队列中取出,推入执行栈,开始执行;
- 如果有需要,会渲染页面;
- 查看宏任务队列,推入执行栈,执行宏任务,开始下一轮事件循环。
举个栗子🌰
下面代码的打印顺序是怎样的呢?
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,欢迎大家学习指正!
技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 "点赞 收藏+关注" ,感谢支持!!