Node.js事件循环滴答到底是什么?


83

我已经对Node.js架构的内部有了更多的了解,并且我看到了很多术语,例如“事件循环的下一个滴答”或nextTick()函数中的“滴答” 。

我还没有看到确切的定义是“滴答声”的确切含义。根据各种文章(例如本篇文章),我已经能够将一个概念拼凑起来,但是我不确定它的准确性如何。

我能否获得有关Node.js事件循环刻度的准确而详细的描述?


因为它的“循环”,它的意思是“下一次循环”,所以它是一个完整的循环,它在没有事件被触发并且nodejs已全部循环以检查是否有任何触发时结束,“ nextTick”意味着下一个当前循环之后。
Gntem

Answers:


155

请记住,虽然JavaScript是单线程的,但是节点的所有I / O和对本机API的调用都是异步的(使用特定于平台的机制),或者在单独的线程上运行。(所有这些都通过libuv处理。)

因此,当套接字上有可用数据或本机API函数返回时,我们需要一种同步方式来调用对刚刚发生的特定事件感兴趣的JavaScript函数。

出于与常规多线程应用程序中遇到的相同原因-竞争条件,非原子内存访问等原因,仅从发生本机事件的线程中调用JS函数是不安全的。

因此,我们要做的是以线程安全的方式将事件放在队列中。在过度简化的伪代码中,如下所示:

lock (queue) {
    queue.push(event);
}

然后,回到主要的JavaScript线程(但在C方面),我们执行以下操作:

while (true) {
    // this is the beginning of a tick

    lock (queue) {
        var tickEvents = copy(queue); // copy the current queue items into thread-local memory
        queue.empty(); // ..and empty out the shared queue
    }

    for (var i = 0; i < tickEvents.length; i++) {
        InvokeJSFunction(tickEvents[i]);
    }

    // this the end of the tick
}

while (true)(这实际上不存在于节点的源代码;这是纯说明性)表示事件循环。内部组件for为队列中的每个事件调用JS函数。

这是一个勾号:与任何外部事件关联的零个或多个回调函数的同步调用。清空队列并返回最后一个函数后,刻度结束。我们回到开头(下一个刻度),并检查在JavaScript运行时从其他线程添加到队列的事件。

什么可以添加到队列中?

  • process.nextTick
  • setTimeout/setInterval
  • I / O(来自fsnet等的东西)
  • crypto的处理器密集型功能,例如加密流,pbkdf2和PRNG(实际上是...的示例)
  • 使用libuv工作队列进行同步C / C ++库调用的任何本机模块看起来都是异步的

2
是的,你钉了这个。我特别想知道的是复制队列并运行副本上的所有事件。虽然现在很有意义。谢谢。
2013年

这是著名的“异步迭代模式”算法吗?
Stef

1
@sanjeev,“常规工作”是什么意思?正在进行的JavaScript应用程序唯一要做的就是处理事件。
josh3736 2014年

2
我想补充一点,在0.10.x中setImmediate也会加入一个函数。
DanielKhan

1
滴答表示事件循环阶段吗?
faressoft

10

对于JavaScript新手来说,一个简单的答案是:

首先要了解的是,JavaScript是一个“单线程环境”。这是指JavaScript在单个线程上从“事件循环”一次执行一个代码块的行为。下面是从凯尔·辛普森(Kyle Simpson)的书ydkJS中摘录的事件循环的基本实现,然后进行了解释:

// `eventLoop` is an array that acts as a queue (first-in, first-out)
var eventLoop = [ ];
var event;

// keep going "forever"
while (true) {
    // perform a "tick"
    if (eventLoop.length > 0) {
        // get the next event in the queue
        event = eventLoop.shift();

        // now, execute the next event
        try {
            event();
        }
        catch (err) {
            reportError(err);
        }
    }
}

第一个while循环模拟事件循环。滴答是事件从“事件循环队列”中出队并执行所述事件。

请参阅“ Josh3796”的响应,以更详细地说明事件的出队和执行中会发生什么。

另外,对于那些对JavaScript有深入了解的人,我建议阅读Kyle Simpson的书。它是完全免费和开源的,可以在以下链接中找到:https : //github.com/getify/You-Dont-Know-JS

我引用的特定部分可以在这里找到:https : //github.com/getify/You-Dont-Know-JS/blob/2nd-ed/sync-async/ch1.md


1

事件循环刻度的非常简单和简短的方法是:

它由节点内部机制使用,在该机制中,当处理队列中的请求集时,将启动滴答声,表示任务已完成


您能否提供一些答案来源?
Kick Buttowski
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.