当前位置: 首页 > 后端技术 > Node.js

节点事件循环(Eventloop)

时间:2023-04-03 15:52:25 Node.js

原文地址:节点事件循环(Eventloop)本文将简单介绍一下节点事件循环的机制,帮助我们理解代码在节点环境下是如何运行的。1.node运行机制node使用V8作为js解析引擎,使用自己设计的libuv进行I/O处理。libuv是一个基于事件的跨平台抽象层,封装了不同操作系统的一些底层特性,对外提供统一的API。事件循环机制也在其中实现。运行机制:①V8引擎解析JavaScript脚本。②解析后的代码调用NodeAPI。③libuv库负责NodeAPI的执行。它将不同的任务分配给不同的线程,形成一个EventLoop(事件循环),并将任务的执行结果以异步的方式返回给V8引擎。④V8引擎将结果返回给用户。2.事件循环libuv引擎中的事件循环分为6个阶段,循环运行。每个阶段都有一个FIFO队列来执行回调。每当进入一个新的阶段,就会从对应的回调队列中取出函数执行。当队列为空或回调执行次数达到系统设定的阈值时,进入下一阶段。流程如下:┌────────────────────────────────┐┌─>│定时器││└────────────────┬──────────────────┘│┌────────────────────────────────────────────────────────┐││等待回调││└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────────────┐││空闲,准备││└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘┌────────────────┐│┌───────────────────────────────────────────────────────────────────────────────────┐│传入:│.........────────────┐└──┤收盘回调│└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘①Timer(定时器):这个阶段执行已经setTimeout()和setInterval()的回调函数。注意:轮询阶段控制计时器何时执行。轮询阶段回调队列执行完后,node会检查是否有定时器超时,如果有则返回定时器阶段执行定时器回调,所以定时器的执行时间是不确定的,而定时器可以在轮询阶段使用正在执行的阻塞回调会导致延迟,节点只保证尽快执行。②Pendingcallbacks:延迟到下一次循环迭代执行的I/O回调。此阶段执行某些系统操作(例如TCP错误类型)的回调。例如,如果TCP套接字在尝试连接时收到ECONNREFUSED,一些*nix系统希望等待报告错误。这将在挂起的回调阶段排队等待执行。③idle、prepare:仅供系统内部使用。④轮询(poll):检索新的I/O事件;执行I/O相关的回调(在几乎所有情况下,除了关闭的回调函数,那些由定时器和setImmediate()调度的),其余的case节点会在合适的时候阻塞在这里。轮询阶段有两个重要功能:1.计算何时应该阻塞并轮询I/O。2.接下来,处理轮询队列中的事件。当事件循环进入轮询阶段并且没有被调度的定时器时,会发生以下两种情况之一:1)如果轮询队列不为空,事件循环将遍历回调队列并同步执行,直到队列耗尽已用尽,或已达到与系统相关的硬限制。2)如果轮询队列为空,还会发生两件事:如果脚本由setImmediate()调度,事件循环将结束轮询阶段并继续检查阶段以执行那些调度的脚本。如果脚本没有被setImmediate()调度,事件循环会等待回调被添加到队列中,然后立即执行。一旦轮询队列为空,事件循环就会检查已达到时间阈值的计时器。如果一个或多个计时器就绪,事件循环将返回到计时器阶段以执行这些计时器的回调。⑤检测(check):这里执行setImmediate()回调函数。⑥关闭回调(closecallbacks):一些关闭回调函数,如:socket.on('close',...)。如果套接字或处理程序突然关闭(例如socket.destroy()),“关闭”事件将在此阶段发出。否则它将通过process.nextTick()发出。