美文网首页
node事件循环(Event loop)

node事件循环(Event loop)

作者: FarmerLZJ | 来源:发表于2021-12-08 09:24 被阅读0次

    原文地址: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() 发出。

    相关文章

      网友评论

          本文标题:node事件循环(Event loop)

          本文链接:https://www.haomeiwen.com/subject/lnnzxrtx.html