浏览器中的事件循环和Node.js中事件循环的区别(经典面试题)

简介: 浏览器中的事件循环和Node.js中事件循环的区别(经典面试题)

前言

众所周知,JavaScript是单线程执行的,指的是一个进程里只有一个主线程。

JavaScript中的进程有:一个浏览器主进程、一个GPU进程、一个网络进程、多个渲染进程和插件进程。
JavaScript中的线程有:GUI渲染线程、JS引擎线程、计时器线程、异步HTTP请求线程、事件触发线程。

node事件循环

timer定时器阶段:执行如setTimeout和setInterval等的回调函数

I/O回调阶段:执行上一轮循环中未执行的I/O回调函数

Idle闲置阶段:仅供系统内部使用

Poll轮询阶段:这是一个至关重要的阶段,系统主要做两件事,一是回到timer阶段执行回调,二是执行I/O回调。会主动检测是否有新的I/O事件,若存在新的I/O事件,则执行其回调函数,适当的条件下,node将阻塞在这里。

check检查阶段:执行setImmediate的回调函数

close callbacks关闭回调阶段:执行socket.close()事件回调

浏览器事件循环

浏览器首先会执行主线程上的代码(相当于宏任务),遇到微任务便将其推入微任务队列中,遇到宏任务便推入宏任务队列中

当主线程中的代码执行完后,会检查微任务队列是否为空,若不为空,则将微任务队列中的微任务推至执行栈中执行。在执行的该微任务的过程中,如果又遇到宏任务则将其推入宏任务队列,遇到微任务则推入微任务队列

当微任务队列执行完为空时,检查宏任务队列是否为空,如不为空,则将对头宏任务推入执行栈开始执行。该过程中,若遇到宏任务则将其推入宏任务队列,若遇到微任务,则推入微任务队列

每当执行完一个宏任务,不管宏任务队列中是否还存在宏任务,都必须去检查微任务队列中是否有微任务,若存在微任务,则开始执行微任务

区别:

  • 在浏览器事件循环中,每执行完一个宏任务,便要检查并执行微任务队列;而node事件循环中则是在“上一阶段”执行完,“下一阶段”开始前执行微任务队列中的任务。也就是说,node中的微任务是在两个阶段之间执行的。如果是node10及其之前版本:要看第一个定时器执行完,第二个定时器是否在完成队列中。
  • 在浏览器事件循环中,process.nextTick()属于微任务,而且和其他微任务的优先级是一样的,不存在哪个微任务的优先级高就先执行谁。但是在node中,process.nextTick()的优先级要高于其他微任务,也就是说,在两个阶段之间执行微任务时,若存在process.nextTick(),则先执行它,然后再执行其他微任务。

例子:

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')
    })
})
Promise.resolve().then(function () {
    console.log('微任务1');
})
console.log('script结束');

浏览器端运行结果

script开始
script结束
微任务1
宏任务1
微任务2
宏任务2
微任务3

node端运行结果

script结束
微任务1
宏任务1
微任务2
宏任务2
微任务3

小结

  • 浏览器是一个宏任务+一个微任务队列
  • node是一个宏任务队列+一个微任务队列


相关文章
|
1天前
|
自然语言处理 JavaScript 前端开发
当面试官再问我JS闭包时,我能答出来的都在这里了。
闭包(Closure)是前端面试中的高频考点,广泛应用于函数式编程中。它不仅指函数内部定义的函数,还涉及内存管理、作用域链和垃圾回收机制。闭包可以让函数访问其外部作用域的变量,但也可能引发内存泄漏等问题。通过合理使用闭包,可以实现模块化、高阶函数和回调函数等应用场景。然而,滥用闭包可能导致代码复杂度增加、调试困难以及潜在的性能问题。为了避免这些问题,开发时应谨慎处理闭包,避免不必要的嵌套,并及时清理不再使用的变量和监听器。
当面试官再问我JS闭包时,我能答出来的都在这里了。
|
1月前
|
Web App开发 前端开发 JavaScript
折腾之王:JavaScript之父Brave浏览器与BAT的诞生
2015年,JavaScript之父Brendan Eich再次创业,推出Brave浏览器和加密货币Basic Attention Token(BAT),旨在颠覆传统广告行业。Brave屏蔽广告、保护隐私,加载速度快;BAT则通过奖励机制让用户、内容创作者和广告主三方受益。尽管面临用户习惯和巨头竞争的挑战,Brave已拥有超4000万月活跃用户,成为全球增长最快的隐私浏览器,引领Web3生态发展。
112 22
折腾之王:JavaScript之父Brave浏览器与BAT的诞生
|
22天前
|
Java 程序员 调度
Java 高级面试技巧:yield() 与 sleep() 方法的使用场景和区别
本文详细解析了 Java 中 `Thread` 类的 `yield()` 和 `sleep()` 方法,解释了它们的作用、区别及为什么是静态方法。`yield()` 让当前线程释放 CPU 时间片,给其他同等优先级线程运行机会,但不保证暂停;`sleep()` 则让线程进入休眠状态,指定时间后继续执行。两者都是静态方法,因为它们影响线程调度机制而非单一线程行为。这些知识点在面试中常被提及,掌握它们有助于更好地应对多线程编程问题。
55 9
|
27天前
|
安全 Java 程序员
Java面试必问!run() 和 start() 方法到底有啥区别?
在多线程编程中,run和 start方法常常让开发者感到困惑。为什么调用 start 才能启动线程,而直接调用 run只是普通方法调用?这篇文章将通过一个简单的例子,详细解析这两者的区别,帮助你在面试中脱颖而出,理解多线程背后的机制和原理。
60 12
|
25天前
|
编译器 Android开发 开发者
Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
Lambda表达式和匿名函数都是Kotlin中强大的特性,帮助开发者编写简洁而高效的代码。理解它们的区别和适用场景,有助于选择最合适的方式来解决问题。希望本文的详细讲解和示例能够帮助你在Kotlin开发中更好地运用这些特性。
29 9
|
3月前
|
JavaScript 前端开发 数据处理
模板字符串和普通字符串在浏览器和 Node.js 中的性能表现是否一致?
综上所述,模板字符串和普通字符串在浏览器和 Node.js 中的性能表现既有相似之处,也有不同之处。在实际应用中,需要根据具体的场景和性能需求来选择使用哪种字符串处理方式,以达到最佳的性能和开发效率。
124 63
|
3月前
|
移动开发 JavaScript 前端开发
一些处理浏览器兼容性问题的JavaScript库
这些库在处理浏览器兼容性问题方面都有着各自的特点和优势,可以根据具体的需求和项目情况选择合适的库来使用,从而提高代码的兼容性和稳定性,为用户提供更好的体验。同时,随着浏览器技术的不断发展,还需要持续关注和学习新的兼容性解决方案。
131 48
|
2月前
|
Java
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
今日分享的主题是如何区分&和&&的区别,提高自身面试的能力。主要分为以下四部分。 1、自我面试经历 2、&amp和&amp&amp的不同之处 3、&对&&的不同用回答逻辑解释 4、彩蛋
|
3月前
|
Java 程序员
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
小米,29岁程序员,分享了一次面试经历,详细解析了Java中&和&&的区别及应用场景,展示了扎实的基础知识和良好的应变能力,最终成功获得Offer。
107 14
|
2月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。