Node.js Event loop 监控器。高的 frequency 和低的持续时间是最理想的 event loop 状态。
上图显示三点半到五点半之间,event loop 的 frequency 骤降,然后 duration 居高不下。
Node.js 是一个基于事件的平台。 这意味着在 Node 中发生的一切都是对事件的反应。通过 Node 的事务会遍历级联的回调(a cascade of callbacks)。
这一切都由一个名为 libuv 的库处理,它提供了一种称为事件循环的机制。
关于 Node.js 的事件循环,有很多误解。
误解1:事件循环机制运行在独立于用户逻辑的单独线程内
误解:
有一个主线程,用户的 JavaScript 代码(userland 代码)在其中运行,另一个主线程运行事件循环。 每次发生异步操作时,主线程都会将工作交给事件循环线程,一旦完成,事件循环线程就会通知主线程执行回调。
正确的理解:
只有一个线程执行 JavaScript 代码,这是运行事件循环的线程。 回调的执行(运行中的 Node.js 应用程序中的每个用户空间代码都是回调)由事件循环完成。
误解2:异步操作通过线程池完成
异步操作,如使用文件系统、执行出站 HTTP 请求或与数据库对话,总是加载到 libuv 提供的线程池中。
正确的理解:
Libuv 默认创建一个包含四个线程的线程池来卸载异步工作。 今天的操作系统已经为许多 I/O 任务提供了异步接口(例如 Linux 上的 AIO)。
只要有可能,libuv 就会使用那些异步接口,避免使用线程池。
这同样适用于第三方子系统,如数据库。 这里驱动程序的作者宁愿使用异步接口也不愿使用线程池。
简而言之:只有在没有其他办法的情况下,才会使用线程池进行异步I/O.
误解3:Event Loop 利用了栈或者队列的数据结构
事件循环不断遍历异步任务的 FIFO,并在任务完成时执行回调。
正确的理解:
虽然涉及到类似队列的结构,但事件循环不会遍历并处理堆栈。 作为一个进程的事件循环是一组具有特定任务的阶段,这些阶段以循环方式处理。