机制区别
- 浏览器事件循环:
- 浏览器事件循环主要围绕页面渲染、用户交互等操作。它的任务队列主要分为宏任务队列和微任务队列。宏任务如
setTimeout
、setInterval
、requestAnimationFrame
等,微任务如 Promise.then
、MutationObserver
等。
- 事件循环过程大致为:从宏任务队列中取出一个任务执行,执行完后清空微任务队列,然后进行页面渲染,接着再从宏任务队列中取任务,如此循环。
- Node.js事件循环:
- Node.js 的事件循环基于 libuv 库实现。它有多个阶段,每个阶段都有一个先进先出的回调队列。主要阶段包括
timers
(处理 setTimeout
和 setInterval
)、I/O callbacks
(处理一些系统调用的回调)、idle, prepare
(内部使用)、poll
(等待新的 I/O 事件,执行 I/O 相关回调)、check
(执行 setImmediate
的回调)、close callbacks
(处理关闭相关的回调)。
- 事件循环过程为:进入
timers
阶段,执行到期的 setTimeout
和 setInterval
回调;然后进入 I/O callbacks
阶段,执行一些系统调用的回调;接着进入 poll
阶段,等待新的 I/O 事件,执行 I/O 相关回调,当有新的 I/O 事件或达到 poll
阶段的超时时间后,进入 check
阶段执行 setImmediate
的回调,最后进入 close callbacks
阶段处理关闭相关回调,之后再回到 timers
阶段开始新的循环。
应用场景区别
- 浏览器事件循环:
- 主要应用于前端页面交互,例如用户点击按钮、滚动页面等操作,以及动画效果实现。比如在实现一个动画,使用
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>
- 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/');
});
任务队列处理区别
- 浏览器事件循环:
setTimeout(() => {
console.log('宏任务');
}, 0);
Promise.resolve().then(() => {
console.log('微任务');
});
// 输出:微任务,宏任务
- Node.js事件循环:
- 在不同阶段处理不同类型的任务。例如
setTimeout
和 setImmediate
的执行顺序问题,在 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
先执行。