JavaScript 事件循环

2025年4月23日 | 阅读 4 分钟

JavaScript 中的事件循环是一种用于管理多个代码块执行的机制,其中包括一些异步任务,如定时器、回调和 Promise。

JavaScript 是单线程的。如果你想在不阻塞主链的情况下管理多个任务的执行,那么你需要使用事件循环。

简而言之,JavaScript 中的事件循环通过高效地处理任务来启用异步编程。它还有助于确保 API 请求、定时器和用户交互等异步操作不会阻塞其他代码的执行。

示例

编译并运行

输出

 
Start
End
Promise Resolved
setTimeout Callback   

说明

在上面的代码中,console.log("Start") 会立即执行。setTimeout 会调度一个回调函数,但不会立即执行。Promise.resolve().then() 创建一个立即执行的 Promise,这允许回调函数被执行。console.log(“Start”) 会先执行。console.log("End") 会立即执行。

事件循环的组成部分

事件循环确保任务按正确的顺序执行,从而实现异步编程。事件循环有两个组成部分:

调用栈 (Call Stack): 在 JavaScript 事件循环中,调用栈用于跟踪所有待执行的操作。当一个函数执行完毕时,它会从栈中弹出。

事件队列 (Event Queue): 事件队列负责管理函数提交到栈中进行处理。它利用队列数据结构,保持操作执行的顺序。定时器和事件等异步任务会在调用栈清空后排队等待执行。

事件循环如何工作?

在 JavaScript 中,事件循环通过以下几个步骤工作:

Event Loop in JavaScript

调用栈 (Call stacks): 在 JavaScript 事件循环中,有一个调用栈以 LIFO(后进先出)的顺序管理函数执行。

Web APIs: 在 JavaScript 中,这包括 setTimeoutsetInterval、fetch、DOM 事件和其他异步操作。

回调队列 (Callback Queue): 当一个异步操作(例如定时器、API 调用或事件)准备好执行时,它会被放入事件队列。

微任务队列 (Microtask Queue): Promises 和其他微任务会被放入微任务队列,该队列在任务队列之前处理。

事件循环 (Event Loop): 它会不断检查调用栈,如果调用栈为空,则将队列中的任务移入栈中执行。

事件循环中的微任务与宏任务

微任务 (Microtasks): 它们是优先级更高的任务,在宏任务之前运行,例如 Promises 和 queueMicrotask()。

宏任务 (Macrotasks): 它们是优先级较低的任务,在微任务之后运行,例如 setTimeout、setInterval 和 DOM 事件。

示例

编译并运行

输出

 
Start
End
Microtask
Macrotask

示例

示例 1:setTimeout

示例

编译并运行

输出

 
Start
End
Inside setTimeout

示例 2:Promise 和微任务

示例

编译并运行

输出

 
Start
End
Inside Promise

示例 3:Promise 与 setTimeout 的对比

示例

编译并运行

输出

 
End
Promise
Timeout

事件循环的阶段

  • 定时器 (Timers): 在此阶段,当 setTimeout() 和 setInterval() 的相应时间到期时,它会执行由它们调度的回调。
  • 待处理回调 (Pending Callbacks): 在此阶段,它处理已推迟到下一个循环迭代的 I/O 回调。
  • 空闲/准备 (Idle/Prepare): 这些阶段主要用于内部记账和设置。
  • 轮询 (Poll Phase): 此阶段检索新的 I/O 事件并运行 I/O 相关回调。
  • 检查 (Check Phase): 此阶段执行使用 setImmediate() 注册的回调。
  • 关闭回调 (Close Callbacks): 此阶段负责清理任务,例如关闭连接或终止服务器。

为什么事件循环很重要?

事件循环使 JavaScript 能够执行非阻塞 I/O 操作,这对于现代 Web 应用程序至关重要。让我们看看它为什么重要:

高效的异步处理

在 JavaScript 中,事件循环会管理数据获取、用户输入处理或使用定时器等任务,而不会阻塞其他代码的执行。

用户交互

在 JavaScript 中,利用事件循环可以让我们在处理多个用户交互的同时执行后台操作,而不会减慢用户界面。

单线程

事件循环通过将任务委托给任务队列并以不阻塞主线程的顺序执行它们来高效地处理多个操作。

结论

总而言之,JavaScript 的事件循环是一种机制,它使单线程语言能够在不阻塞主线程的情况下管理异步任务。它与处理同步代码的调用栈以及异步任务等待执行的事件队列一起工作。