非阻塞函数返回后的Node.js回调处理

时间:2016-04-03 06:07:06

标签: javascript node.js asynchronous nonblocking

我正在阅读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请求处理程序)一样?换句话说,可以在服务器回调块中包含错误编写的代码吗? (我认为答案是肯定的,但想知道我是否正确。)
  5. 这是一个类似的问题,有很好的答案,但细微差别。这个链接的问题解决了用户代码的异步性,但其中一个答案似乎包含了我的问题的偶然答案。我对Node的内部工作感兴趣,用户从不与之交互,例如,谁在Node阻塞时管理新客户端请求插入事件队列,同样用于回调等。 Is NodeJS really Single-Threaded?

2 个答案:

答案 0 :(得分:2)

首先,它有助于从这开始:

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

现在按每个问题的顺序打破这个问题:

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

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

异步I / O操作位于不同的线程中,并且可以在Node执行其他操作时将内容存入队列。当Node完成那件事时,它可以处理队列中的事情。

  
      
  1. 异步功能的类似问题'回调...当Node.js已经处理了一些回调或事件时,谁在监听和管理传入的回调,这样回调在处理过程中就不会丢失?
  2.   

同样,它不会因为它是队列而丢失。它是该数据结构的基本组成部分。该事件将在队列中等待,直到某些事情从队列中取出。

,无论当时是否正在倾听,它都不会消失。

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

来自异步函数的回调将进入队列,没有任何方式来中断"中断"事件循环的当前流程。事件循环确实有多个不同的订单,因此可能不会像异步IO事件一样对待(我无法记得),但回调仍然需要轮流等待。

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

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

function add(a, b, cb) { cb(a + b) }

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

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

希望有帮助,如果有什么不清楚,请告诉我!

答案 1 :(得分:1)

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

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

  1. 还涉及其他线程。
  2. 事件循环应该是类似队列的数据结构,可由许多线程访问
  3. 主要是重新进入事件循环(在队列末尾)。但是有办法把它放在前面。 (需要检查)
  4. 是。例如。如果你使用fs.readFileSync,它会阻塞服务器一段时间。
  5. 事件循环:http://2014.jsconf.eu/speakers/philip-roberts-what-the-heck-is-the-event-loop-anyway.html

    我已经从记忆中写下来了。如果这对您有帮助,我可以尝试查找引用。