MST

星途 面试题库

面试题:Node.js事件循环与浏览器事件循环的区别

我们知道浏览器也有事件循环机制,对比Node.js的事件循环,它们在机制、应用场景、任务队列处理等方面有哪些显著的区别?请举例说明。
36.0万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

机制区别

  1. 浏览器事件循环
    • 浏览器事件循环主要围绕页面渲染、用户交互等操作。它的任务队列主要分为宏任务队列和微任务队列。宏任务如 setTimeoutsetIntervalrequestAnimationFrame 等,微任务如 Promise.thenMutationObserver 等。
    • 事件循环过程大致为:从宏任务队列中取出一个任务执行,执行完后清空微任务队列,然后进行页面渲染,接着再从宏任务队列中取任务,如此循环。
  2. Node.js事件循环
    • Node.js 的事件循环基于 libuv 库实现。它有多个阶段,每个阶段都有一个先进先出的回调队列。主要阶段包括 timers(处理 setTimeoutsetInterval)、I/O callbacks(处理一些系统调用的回调)、idle, prepare(内部使用)、poll(等待新的 I/O 事件,执行 I/O 相关回调)、check(执行 setImmediate 的回调)、close callbacks(处理关闭相关的回调)。
    • 事件循环过程为:进入 timers 阶段,执行到期的 setTimeoutsetInterval 回调;然后进入 I/O callbacks 阶段,执行一些系统调用的回调;接着进入 poll 阶段,等待新的 I/O 事件,执行 I/O 相关回调,当有新的 I/O 事件或达到 poll 阶段的超时时间后,进入 check 阶段执行 setImmediate 的回调,最后进入 close callbacks 阶段处理关闭相关回调,之后再回到 timers 阶段开始新的循环。

应用场景区别

  1. 浏览器事件循环
    • 主要应用于前端页面交互,例如用户点击按钮、滚动页面等操作,以及动画效果实现。比如在实现一个动画,使用 requestAnimationFrame 来不断更新动画的每一帧,它利用浏览器事件循环在合适的时间进行页面渲染,保证动画流畅。
    • 示例代码:
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF - 8">
  <title>动画示例</title>
</head>

<body>
  <div id="box" style="width:100px;height:100px;background - color:red;"></div>
  <script>
    let pos = 0;
    function animate() {
      const box = document.getElementById('box');
      pos += 5;
      box.style.left = pos + 'px';
      if (pos < 300) {
        requestAnimationFrame(animate);
      }
    }
    requestAnimationFrame(animate);
  </script>
</body>

</html>
  1. Node.js事件循环
    • 适用于服务器端编程,处理大量的 I/O 操作,如网络请求、文件读取等。例如在一个基于 Node.js 的 Web 服务器中,处理客户端的 HTTP 请求,通过事件循环高效地处理多个请求而不会阻塞线程。
    • 示例代码(简单的 Node.js HTTP 服务器):
const http = require('http');
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content - Type': 'text/plain' });
  res.end('Hello, World!\n');
});
server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

任务队列处理区别

  1. 浏览器事件循环
    • 宏任务执行后,立即清空微任务队列。例如:
setTimeout(() => {
  console.log('宏任务');
}, 0);
Promise.resolve().then(() => {
  console.log('微任务');
});
// 输出:微任务,宏任务
  1. Node.js事件循环
    • 在不同阶段处理不同类型的任务。例如 setTimeoutsetImmediate 的执行顺序问题,在 I/O 操作之后,setImmediate 会在 setTimeout 之前执行(前提是两者都在 I/O 操作之后被调用)。
const fs = require('fs');
fs.readFile(__filename, () => {
  setTimeout(() => {
    console.log('setTimeout');
  }, 0);
  setImmediate(() => {
    console.log('setImmediate');
  });
});
// 输出:setImmediate,setTimeout
  • 因为 setImmediate 是在 check 阶段执行,setTimeout 是在 timers 阶段执行,I/O 操作完成后先进入 check 阶段,所以 setImmediate 先执行。