【问题标题】:Node.js callback handling after nonblocking function returns非阻塞函数返回后的 Node.js 回调处理
【发布时间】:2023-04-05 21:35:01
【问题描述】:

我正在阅读一本 Node.js 的书,试图清楚地了解 Node.js 如何处理事件、异步函数及其回调、非阻塞 I/O 等。以下是我如何处理的简要提要了解 事件循环 基础知识,然后,一些我无法在书中找到明确答案的问题。如果我的基本理解有任何错误,请纠正我。然后问题接踵而至。

据我了解,Node.js 在单个线程上运行所有功能。这包括事件循环。换句话说,当一个事件发生时,例如HTTP 请求,该请求进入事件队列。事件循环本身一次从队列中拉出一个事件并对其进行整体处理。这可能意味着立即返回一个简单的结果,或者在 I/O 到第三方(如数据库或文件系统)的情况下,进行非阻塞、异步调用,并通过回调告诉系统何时该做什么异步功能完成。同时,队列中的所有其他事件都在等待。如果开发人员编写的方法不会异步或将工作卸载给工作人员,则在处理任务时整个服务器将挂起。

如果其中有任何错误,请澄清,因为这可能会影响我对以下问题的答案的理解,我希望这些问题不会愚蠢。

  1. 文件系统、数据库和其他此类调用不会阻塞,因为 Node.js 将它们卸载到异步调用,但如果 Node.js 是单线程的,谁在监听新事件并管理事件循环?当 Node.js 正在处理一些事件时,谁在监听和管理新传入事件的队列,以便在 Node.js 的注意力在别处时不会丢失它们?我是否从根本上误解了这是如何工作的?除了运行我们代码的引擎部分之外,是否有像守护程序在运行之类的东西来管理事件队列?
  2. 异步函数回调的类似问题......当 Node.js 已经在处理一些回调或事件时,谁在监听和管理传入的回调,以便回调在处理过程中不会因为到达而丢失?李>
  3. 当异步函数完成时,回调是中断事件循环并立即进行控制,还是异步函数的返回作为队列末尾的新事件重新进入事件循环并等待轮到自己再次?换句话说,来自异步函数的回调是像任何其他事件一样处理,还是不同?如果区别对待,如何处理?这是一个根本愚蠢的问题吗?
  4. 回调是否可以阻塞,就像写得不好的事件处理程序(例如 HTTP 请求处理程序)一样?换句话说,回调中包含的写得不好的代码会阻塞服务器吗? (我认为答案是肯定的,但想知道我是否正确。)

这是一个类似的问题,答案很好,但细微差别略有不同。这个链接的问题解决了与用户代码有关的异步问题,但其中一个答案似乎包含对我的问题的偶然答案。我对用户从不与之交互的 Node 的内部工作也很感兴趣,例如谁在 Node 阻塞时管理新的客户端请求插入到事件队列中,对于回调等也是如此。 Is NodeJS really Single-Threaded?

【问题讨论】:

    标签: javascript node.js asynchronous nonblocking


    【解决方案1】:

    首先,从这里开始会有所帮助:

    “Node.js 是单线程的”这句话有点误导并且在技术上是不正确的。对于代码中的所有意图和目的,您的代码是单线程的,但 Node 本身不是。 Node 中有一些 API 和操作(通常是异步 I/O),它们将在内核或 LibUV 的线程池中使用不同的线程。

    现在按每个问题的顺序来分解:

    1. 文件系统、数据库和其他此类调用不会阻塞,因为 Node.js 将它们卸载到异步调用,但如果 Node.js 是单线程的,谁在监听新事件并管理事件循环?当 Node.js 正在处理一些事件时,谁在监听和管理新传入事件的队列,以便在 Node.js 的注意力在别处时不会丢失它们?我是否从根本上误解了这是如何工作的?除了运行我们代码的引擎部分之外,是否有守护进程之类的运行或其他东西来管理事件队列?

    当 Node 正在处理一些事件时,没有人在监听队列。它们不会丢失,因为它是一个队列。它会一直等到 Node 完成它正在做的事情,这样它就可以返回队列来检查它是否有下一步要做的事情。这是 Node 的“事件循环”的一部分,为什么阻塞代码(不允许 Node 返回到事件循环顶部的代码,或者需要很长时间才能这样做)是有问题的。

    异步 ​​I/O 操作在单独的线程中,并且可以在 Node 执行其他操作时将内容存放在队列中。当 Node 做完这件事后,它就可以处理队列中的事情了。

    1. 异步函数回调的类似问题......当 Node.js 已经在处理一些回调或事件时,谁在监听和管理传入的回调,以便回调在处理过程中不会由于其到达而丢失?李>

    同样,它不会丢失,因为它是一个队列。它是该数据结构的基本部分。该事件将在队列中等待,直到有东西将其从队列中取出。无论当时是否有任何东西在听,它都不会消失,它必须被消耗掉。

    1. 当异步函数完成时,回调是中断事件循环并立即进行控制,还是异步函数的返回作为队列末尾的新事件重新进入事件循环并等待轮到自己再次?换句话说,来自异步函数的回调是像任何其他事件一样处理,还是不同?如果区别对待,如何处理?这是一个根本愚蠢的问题吗?

    来自异步函数的回调将进入队列,没有任何方法可以“中断”事件循环的当前流程。事件循环确实有多个不同的顺序,所以它可能不像异步 IO 事件那样被对待(我不记得了),但回调仍然需要等待轮到它。

    1. 回调是否可以阻塞,就像写得不好的事件处理程序(例如 HTTP 请求处理程序)一样?换句话说,回调中包含的糟糕的代码会阻塞服务器吗? (我认为答案是肯定的,但想知道我是否正确。)

    是的,回调只是一个函数调用,而函数调用不一定是异步的。您可以编写这样的代码来阻止:

    function add(a, b, cb) { cb(a + b) }
    
    async.whilst(
      function() { return true },
      function(cb) { add(1 + 1, cb) },
      function() { console.log('Done!') }
    )
    

    虽然此代码在技术上使用回调,但它不会做任何异步操作,因此 Node 将继续评估函数调用并且从不检查事件循环。也就是说,您很少看到这种情况,因为回调通常涉及异步操作,或者它们不是为了使用回调而编写的。

    希望对您有所帮助,如果有任何不清楚的地方,请告诉我!

    【讨论】:

    • 感谢您的回答,我有一个后续问题...我了解队列的工作原理,并且节点在处理时无法从事件队列中拉出。在我的问题中,我想问:当 Node 阻塞时,谁管理 new 客户端请求 onto 队列的插入?是否有一个单独的专用线程?您是否有任何资源可以让我对此进行一些额外的阅读?
    • @fts_acer 队列在线程之间共享。每当发生异步事件时,都会使用单独的 I/O 线程来处理该事件。由于该线程与 Node 共享事件队列,因此当它完成操作时,它会将结果推送到队列中并完成执行。
    • @fts_acer 由于您指的是“新客户端请求”,我假设您在谈论套接字服务器。当您调用listen() 时,一个新线程开始在该端口上侦听。在 C 语言中,该调用是阻塞的,因此线程会阻塞,直到有请求进来。当它接收到请求时,它会将其推送到队列中,然后循环返回以阻塞,直到另一个请求进来。当节点将这些请求从队列中拉出时有机会。
    • @fts_acer 如果您对内部工作原理更加好奇,我建议您阅读libuv documentation。 Node 使用 libuv 来执行异步任务。
    • @fts_acer 只是想提醒一下,如果此答案(或此处的其他答案之一)解决了您的问题,请考虑将其标记为已解决!
    【解决方案2】:

    从各种来源回忆,我随着时间的推移阅读。

    Node.js 并不完全是单线程的。它将磁盘、数据库、HTTP API 调用卸载到其他线程,这些线程一旦完成就将它们的回调排入事件循环中。

    1. 还涉及其他线程。
    2. 事件循环应该是一个类似队列的数据结构,可以被很多线程访问
    3. 主要是重新进入事件循环(在队列末尾)。但是有办法把它放在前面。 (需要检查)
    4. 是的。例如。如果你使用 fs.readFileSync,它会阻塞服务器一段时间。

    事件循环:http://2014.jsconf.eu/speakers/philip-roberts-what-the-heck-is-the-event-loop-anyway.html

    我是凭记忆写的。如果这对您有帮助,我可以尝试查找参考资料。

    【讨论】:

    • 我试图澄清我的第四个问题。你的回答很有帮助。在大多数情况下,它证实了我的怀疑。您可能知道的任何其他资源可以帮助我更深入地理解将非常有帮助,到目前为止我发现的资源只提供了足够的基本理解供开发人员使用,我正在尝试研究 Node.js 是如何工作的引擎盖。谢谢,您已经提供了帮助!
    猜你喜欢
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 2012-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多