Node.js事件循环究竟是什么?

时间:2013-11-06 20:57:24

标签: node.js javascript-events

我已经越来越多地进入node.js体系结构的内部,我看到的一个术语是“tick”,如“事件循环的下一个tick”或函数nextTick()

我没有看到的是对什么是“滴答”的确切定义。基于各种文章(such as this one),我已经能够将一个概念拼凑在一起,但我不确定它是多么准确。

我能获得node.js事件循环的精确详细描述吗?

4 个答案:

答案 0 :(得分:121)

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

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

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

所以我们所做的是以线程安全的方式将事件放在队列中。在过度简化的伪代码中,类似于:

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

然后,回到主要的线程(但在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函数。

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

什么可以添加到队列?

  • process.nextTick
  • setTimeout / setInterval
  • I / O(来自fsnet的内容,等等)
  • crypto处理器密集型函数,如加密流,pbkdf2和PRNG(实际上是......的一个例子)
  • 使用libuv work queue进行同步C / C ++库调用的任何本机模块都是异步的

答案 1 :(得分:5)

对JavaScript新手来说更简单的答案:

首先要理解的是JavaScript是一个单线程环境&#34;。这是指JavaScript一次一个地执行代码块的行为#34;事件循环&#34;在一个线程上。下面是从Kyle Simpson的书ydkJS中获取的事件循环的基本实现,然后是一个解释:

good

第一个while循环模拟事件循环。 tick是从&#34;事件循环队列中排除事件&#34;以及所述事件的执行。

请参阅&#39; Josh3796&#39;有关事件的出列和执行中发生的事情的更详细说明。

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

我引用的具体部分可以在这里找到:https://github.com/getify/You-Dont-Know-JS/blob/master/async%20%26%20performance/ch1.md#event-loop

答案 2 :(得分:1)

“tick”是指完全通过事件循环。令人困惑的是,setImmediate() 需要一个滴答来运行,而 process.nextTick() 更直接,因此这两个函数应该交换名称。

答案 3 :(得分:0)

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

节点内部机制使用它,当队列中的请求集被处理后,滴答声被启动,代表任务的完成