关于node.js:node事件循环Event-loop

9次阅读

共计 1883 个字符,预计需要花费 5 分钟才能阅读完成。

原文地址:node 事件循环(Event loop)

本文将简述 node 事件循环的机制,帮忙咱们了解 node 环境中代码是如何运行的。

1.node 运行机制

node 应用 V8 作为 js 解析引擎,I/ O 解决应用了本人设计的 libuv,libuv 是一个基于事件的跨平台形象层,封装了不同操作系统一些底层个性,对外提供对立的 API, 事件循环机制也是它外面的实现。

运行机制:

① V8 引擎解析 JavaScript 脚本。

② 解析后的代码,调用 Node API。

③ libuv 库负责 Node API 的执行。它将不同的任务分配给不同的线程,造成一个 Event Loop(事件循环),以异步的形式将工作的执行后果返回给 V8 引擎。

④ V8 引擎再将后果返回给用户。

2. 事件循环

libuv 引擎中的事件循环分为 6 个阶段,循环运行。

每个阶段都有一个 FIFO 队列来执行回调。每当进入新阶段的时候,都会从对应的回调队列中取出函数去执行,当队列为空或者执行的回调数量达到零碎设定的阈值,就会进入下一阶段。

流程如下:


   ┌───────────────────────────┐
┌─>│           timers          │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │     pending callbacks     │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │       idle, prepare       │
│  └─────────────┬─────────────┘      ┌───────────────┐
│  ┌─────────────┴─────────────┐      │   incoming:   │
│  │           poll            │<─────┤  connections, │
│  └─────────────┬─────────────┘      │   data, etc.  │
│  ┌─────────────┴─────────────┐      └───────────────┘
│  │           check           │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
└──┤      close callbacks      │
   └───────────────────────────┘
  

① 定时器 (timers):本阶段执行曾经被 setTimeout() 和 setInterval() 的回调函数。

留神:轮询阶段管制何时定时器执行。 轮询阶段回调队列执行结束后,node 会查看是否有定时器到期,如果有,则回到 timers 阶段执行定时器回调,所以定时器的执行工夫不是确定的,定时器有可能被轮询阶段正在执行的回调阻塞导致提早,node 只保障保障尽快执行。

② 待定回调 (pending callbacks):执行提早到下一个循环迭代的 I/O 回调。

此阶段对某些零碎操作(如 TCP 谬误类型)执行回调。例如,如果 TCP 套接字在尝试连贯时接管到 ECONNREFUSED,则某些 *nix 的零碎心愿期待报告谬误。这将被排队以在 挂起的回调 阶段执行。

③ idle, prepare:仅零碎外部应用。

④ 轮询 (poll):检索新的 I/O 事件; 执行与 I/O 相干的回调(简直所有状况下,除了敞开的回调函数,那些由计时器和 setImmediate() 调度的之外),其余状况 node 将在适当的时候在此阻塞。

轮询 阶段有两个重要的性能:

1. 计算应该阻塞和轮询 I/O 的工夫。

2. 接着,解决轮询队列里的事件。

当事件循环进入轮询阶段且没有被调度的计时器时,将产生以下两种状况之一:

1) 如果轮询队列不是空的,事件循环将循环拜访回调队列并同步执行它们,直到队列已用尽,或者达到了与零碎相干的硬性限度。2) 如果轮询队列是空的,还有两件事产生:如果脚本被 setImmediate() 调度,则事件循环将完结 轮询 阶段,并持续 查看 阶段以执行那些被调度的脚本。如果脚本未被 setImmediate() 调度,则事件循环将期待回调被增加到队列中,而后立刻执行。

一旦 轮询 队列为空,事件循环将查看 _已达到工夫阈值的计时器_。如果一个或多个计时器已准备就绪,则事件循环将绕回计时器阶段以执行这些计时器的回调。

⑤ 检测 (check):setImmediate() 回调函数在这里执行。

⑥ 敞开的回调函数 (close callbacks):一些敞开的回调函数,如:socket.on(‘close’, …)。

如果套接字或处理函数忽然敞开(例如 socket.destroy()),则 ’close’ 事件将在这个阶段收回。否则它将通过 process.nextTick() 收回。

正文完
 0