为什么Node.JS中的函数和callback是非阻塞的?

Node对新手的理解是,如果我重写同步或线内代码以利用函数/callback,我可以确保我的代码是非阻塞的。 我很好奇这是如何工作的事件堆栈方面。 从这里简单的例子: 不明白的callback – Stackoverflow是这将阻止:

var post = db.query("select * from posts where id = 1"); doSomethingWithPost(post) doSomethingElse(); 

虽然这不会:

 callback = function(post){ doSomethingWithPost(post) } db.query("select * from posts where id = 1",callback); doSomethingElse(); 

好的,我明白我们应该使用callback。 但就事件堆栈而言,为什么这个工作? Javascript是单线程的..在第一个例子中,第一行使用了昂贵的阻塞I / O操作。 第二行不能执行,直到第一行完成。 这是因为第2行需要来自第1行的信息吗? 还是因为I / O事件只是从根本上阻止了操作,意味着他们抓住了控制权,并且在完成之前不会退还…

在第二个例子中,昂贵的I / O已经被移入了一个函数,现在我们有了一个callback函数。 当然,callback不能执行,直到I / O完成..这不会改变。 因此,在一到二之间执行所花费的时间的差异主要是如果第二个请求到达服务器将会发生什么。

如果第二个请求遇到示例一,它将不能够处理,直到请求1完成,因为阻塞操作..但在这个例子中,..将操作移动到函数自动产生subprocess或作为multithreading? 如果Javscript是单线程的,这将仍然会造成一个问题,除非有一些并行处理的方法..一个函数/callback只保证是非阻塞如果我们使用非阻塞技术,如subprocess等。 。

想象一下你在一家面包店经营收银机。 您按顺序和同步地处理您的客户,如下所示:

  1. 点单
  2. 告诉面包师烘烤面包
  3. 等到面包烘烤
  4. 收取金钱
  5. 送面包
  6. GOTO 1 – 下一个客户

这将是非常缓慢的。 现在,请尝试按顺序执行订单,但是要asynchronous处理您的客户:

  1. 点单
  2. 告诉面包师烘烤面包,并在完成后通知你。 通知时:
    1. 收取金钱
    2. 送面包
  3. GOTO 1 – 下一个客户

更新:我重构了上述,所以它更接近于callback。 收银员在向面包师发出订单后会立即进行第3步。 当面包师通知你面包已经准备就绪时,你会点击步骤2.1。

以这种方式,你仍然可以提供尽可能多的面包 – 你只能卖面包,而面包师可以烘烤。 但是,您可以更高效地处理您的客户,因为您无需等待订单回来,而是开始处理下一位客户。

现在,你可以对此进行各种各样的想象,并预付款,并告诉客户拿起桌子另一端的面包,或类似的东西。 我觉得星巴克是这样“相当”的。 收银员接受订单,发出一些东西的要求,并告诉客户等待,直到所有东西都站在取货区域。 超高效。

现在,想象你的朋友开始经营另一台收银机。 他遵循你的asynchronous例子。 你可以处理更多的客户,甚至更快! 请注意,你唯一需要做的就是把你的朋友放在那里,并给他你的工作stream程。

你和你的朋友是两个并行运行的单线程事件循环。 这类似于两个node.js进程的请求。 你不需要任何复杂的事情来并行化,你只需要运行一个事件循环。

所以,不,“将操作移入function”不会“自动产生subprocess”。 他们更类似于警报 – 当这个完成时,通知我,让我拿起这个点,“这一点”是你的callback代码。 但是callback仍然会在相同的进程和相同的线程中执行。

现在,node.js也为IO操作一个内部线程池。 这是抽象的离开你:继续面包店的比喻,让我们说,你有一个面包师“面包师” – 站在收银机,你不必知道这一点。 你只要给他们订单(“一个酵母面包”),并通知你已经完成了这个订单。 但面包师在他们自己的“贝克池”里并行烘焙面包。

我英文不好,所以我不明白你的意思。 但是我可以说“multithreading”和“asynchronous”是相似但不同的术语。 即使单线程可以形成“asynchronous”。

这个文档不适用于节点(这是一个pythonasynchronous框架“扭曲”),但可能会对你有所帮助。

对不起我英文不好。