Node JS SetTimeOut回调

时间:2018-05-30 00:14:38

标签: javascript node.js

我一直在新波士顿频道(链接https://www.youtube.com/watch?v=KsjrN-T3ZCs)进行节点JS培训。关于Node如何提供更好性能的示例如下所示



function placeAnOrder(orderNumber) {
    console.log("Order placed", orderNumber);
    cookAndDeliver(function () {
        console.log("Delivered order", orderNumber);
    });
};


function cookAndDeliver(callback){
    setTimeout(callback, 5000);
};


placeAnOrder(1);
placeAnOrder(11);
placeAnOrder(111);
placeAnOrder(1111);
placeAnOrder(11111);




如果您运行样本,您会注意到首先所有订单一次放置,这是正常的,然后所有订单也交付一次,这是不正常的,因为已经应用了5秒的超时限制每次通话。

视频给出的解释是回调是非阻碍性的,代码将不受干扰地执行,我同意,我不知道的是为什么节点没有遵守超时值?< / p>

我的猜测是,因为它以异步模式运行,这意味着一个单独的线程将处理每个调用,我的假设是正确的吗?

2 个答案:

答案 0 :(得分:3)

以下是事件的顺序:

  1. 先呼叫placeAnOrder()
  2. 调用cookAndDeliver()
  3. 调用setTimeout()
  4. setTimeout()从现在起安排计时器事件5秒钟并立即返回。
  5. 拨打第二个placeAnOrder()
  6. 调用cookAndDeliver()
  7. 调用setTimeout()
  8. setTimeout()从现在起安排计时器事件5秒钟并立即返回。
  9. 拨打第二个placeAnOrder()
  10. 调用cookAndDeliver()
  11. 调用setTimeout()
  12. setTimeout()从现在起安排计时器事件5秒钟并立即返回。
  13. 重复这两次,总计5个计时器从现在起计约5秒钟
  14. Javascript解释器将控制权返回给事件循环,因为它暂时没有进一步的操作
  15. 然后大约5秒后,Javascript的内部部分将第一个计时器事件放入事件队列
  16. 如果Javascript解释器当时没有执行任何操作,则会触发该事件并调用与该计时器事件关联的回调。
  17. 该回调执行。
  18. 当回调执行时,事件队列中还有另一个计时器事件,JS解释器调用它的回调来处理它。
  19. 在完成回调之后,将从事件队列中一次一个地拉出接下来的3个计时器事件,并执行它们的回调。
  20. 这里没有Javascript线程。 node.js中的Javascript是单线程的。一切都通过中央事件队列。可能有Javascript内部使用线程来执行异步操作(例如,异步文件I / O确实使用其实现内部的线程,但不是用于运行Javascript)。当这些线程完成后,它们将一个事件放入事件队列中,当单个node.js Javascript线程完成它正在执行的操作时,它会从事件队列中获取下一个事件并执行与之关联的回调。 / p>

      

    我的猜测是,因为它以异步模式运行,这意味着一个单独的线程将处理每个调用,我的假设是正确的吗?

    不,这不正确。 setTimeout()计划未来某个时间的计时器事件。没有与计时器事件关联的Javascript线程。可能有也可能没有单个系统线程来管理所有定时器事件(这是特定于实现的并且并不重要 - 也可能是每当Javascript返回到事件循环时,它只是检查它是否有时间到触发下一个计时器事件)。当计时器到达的时间到来时,会将事件插入到Javascript事件队列中。然后JS解释器从事件循环中获取该事件,下次完成处理并寻找下一个要处理的事件。

      

    有关Node如何提供更好性能的示例如下所示

    我认为他们试图表明的是,由于node.js是异步事件驱动设计,因此定时器等异步事件没有多个线程。这允许它在同时存在大量异步操作时更好地扩展,因为它的模型比每个定时器都有系统线程的模型更有效。

      

    如果您运行样本,您会注意到首先所有订单一次放置,这是正常的,然后所有订单也交付一次,这是不正常的,因为已经应用了5秒的超时限制每次通话。

    代码实际上连续运行了5个setTimeout()个调用,所有这些调用都设置了一个计时器,从现在开始激活5秒。 setTimeout()是非阻止的。这意味着它从现在开始计划定时器5秒钟,然后立即进入下一行代码,该代码也从现在开始计划定时器5秒。因此,你最终会安排5个计时器,从现在开始大约5秒钟(从一个setTimeout()调用到下一个调用的执行时间可能只有几毫秒。最终结果是所有5个计时器都会在5秒钟,他们将按计划的顺序开火。

      

    视频给出的解释是回调是非阻碍性的,代码将不受干扰地执行,我同意,我不知道的是为什么节点不遵守超时值?

    因为setTimeout()是非阻塞的(与node.js中的所有异步操作一样)。它会在未来的某个时间安排计时器,然后立即返回(这是非阻塞部分)。它不会等待5秒钟才能返回。它会立即返回并执行下一个代码。然后从现在开始5秒(当JS解释器没有别的事情可做)时,将调用计时器回调。

答案 1 :(得分:1)

它确实遵守超时。超时是针对回调而不是函数的执行。所以发生的事情是所有的函数调用都是异步执行的,它们都等了五秒钟,它们都返回了。所以他们在开始和结束之间都花了五秒钟。在第二个函数完成之前,Node不必等待第一个函数完成。

基本上是一个非常重要的例子,即等待数据库调用。在发送第二个db调用之前,您不必等待一个db调用完成。如果db是线程化的,你可以同时获得结果。