js eventloop实现
JavaScript 事件循环实现原理
JavaScript 的事件循环(Event Loop)是其异步编程的核心机制,通过单线程处理非阻塞 I/O 操作。以下是其实现的关键组成部分:
调用栈(Call Stack)
调用栈用于跟踪当前执行的函数。当函数被调用时,它会被推入栈顶;执行完毕后弹出。同步代码按顺序执行,阻塞栈直到完成。
function foo() {
console.log('foo');
}
function bar() {
foo();
console.log('bar');
}
bar();
// 输出顺序: foo → bar
任务队列(Task Queue)
异步操作(如 setTimeout、fetch)的回调函数会被放入任务队列。事件循环在调用栈为空时,将队列中的任务推入栈执行。
console.log('Start');
setTimeout(() => console.log('Timeout'), 0);
console.log('End');
// 输出顺序: Start → End → Timeout
微任务队列(Microtask Queue)
Promise 和 MutationObserver 的回调属于微任务,优先级高于普通任务(宏任务)。每次调用栈清空后,会先处理所有微任务。

Promise.resolve().then(() => console.log('Microtask'));
setTimeout(() => console.log('Macrotask'), 0);
// 输出顺序: Microtask → Macrotask
事件循环流程
- 执行同步代码:填充调用栈直至清空。
- 检查微任务队列:全部执行完毕,直到队列为空。
- 渲染更新(如需要):执行 UI 渲染。
- 处理宏任务:取一个任务执行,重复步骤 2-4。
代码示例分析
console.log('Script start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
Promise.resolve()
.then(() => console.log('Promise 1'))
.then(() => console.log('Promise 2'));
console.log('Script end');
// 输出顺序:
// Script start → Script end → Promise 1 → Promise 2 → setTimeout
常见异步场景
- 宏任务:
setTimeout、setInterval、I/O 操作、UI 渲染。 - 微任务:
Promise.then、queueMicrotask、MutationObserver。
Node.js 与浏览器的差异
- Node.js:使用 libuv 实现事件循环,包含多个阶段(如
poll、check)。 - 浏览器:由渲染引擎(如 V8)管理,与 DOM 渲染紧密结合。
通过理解事件循环的优先级和队列机制,可以避免常见的异步陷阱(如竞态条件),并优化代码执行顺序。






