【问题标题】:What exactly is a Node.js event loop tick?Node.js 事件循环滴答到底是什么?
【发布时间】:2013-11-18 07:33:35
【问题描述】:

我一直在深入了解 Node.js 架构的内部结构,我经常看到的一个术语是“tick”,例如“事件循环的下一个滴答声”或函数 nextTick()

我还没有看到关于“tick”到底是什么的可靠定义。根据各种文章 (such as this one),我已经能够在脑海中拼凑出一个概念,但我不确定它有多准确。

我能否获得关于 Node.js 事件循环标记的准确而详细的描述?

【问题讨论】:

  • 因为它的“循环”,它的意思是“下一次循环”,所以打勾它是一个完整的循环,它在没有事件被触发并且nodejs已经循环所有以检查是否触发任何事件时结束, "nextTick" 表示当前循环之后的下一个循环。

标签: node.js message-queue event-loop


【解决方案1】:

请记住,虽然 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)(实际上并不存在于 node 的源代码中;这纯粹是说明性的)代表 事件循环。内部 for 为队列中的每个事件调用 JS 函数。

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

什么可以添加到队列中?

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

【讨论】:

  • 是的,你成功了。队列的复制和运行副本上的所有事件是我特别想知道的。不过现在很有意义。谢谢。
  • 这是著名的“异步迭代模式”算法吗?
  • @sanjeev,你所说的“常规工作”是什么意思?正在进行的 JavaScript 应用程序唯一要做的就是处理事件。
  • 我想在 0.10.x 中添加 setImmediate 也将加入一个函数。
  • 打勾是否意味着事件循环阶段?
【解决方案2】:

为 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 循环模拟事件循环。 tick 是事件从“事件循环队列”中出列并执行该事件。

请参阅“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

【讨论】:

  • 这让我很困惑,因为这个答案让我觉得只有一个队列。并且只有在该队列中取消一个事件才被认为是一个滴答声。我从其他一些 Internet 来源中看到滴答声意味着处理单个阶段队列中的所有事件。
【解决方案3】:

Event Loop 打勾的非常简单简短的方法是:

它由节点内部机制使用,当处理队列上的一组请求时,会启动表示任务完成的滴答声

【讨论】:

  • 你能提供一些答案吗?
【解决方案4】:

“滴答”是指完整地通过事件循环。令人困惑的是,setImmediate() 需要一个滴答声才能运行,而 process.nextTick() 更直接,所以这两个函数应该换个名字。

【讨论】:

    猜你喜欢
    • 2019-02-20
    • 1970-01-01
    • 2015-10-13
    • 2018-08-30
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 2018-09-27
    相关资源
    最近更新 更多