[英]Node.js is not a good option for file uploads (and all event-loop based languages) - is that true?
[英]Node.js Event-Loop Mechanism
我正在学习 Node.js 中的 Event-Loop 的机制,并且我正在做一些练习,但有一些困惑,如下所述。
const fs = require("fs");
setTimeout(() => console.log("Timer 1"), 0);
setImmediate(() => console.log("Immediate 1"));
fs.readFile("test-file-with-1-million-lines.txt", () => {
console.log("I/O");
setTimeout(() => console.log("Timer 2"), 0);
setTimeout(() => console.log("Timer 3"), 3000);
setImmediate(() => console.log("Immediate 2"));
});
console.log("Hello");
我预计会看到以下 output:
你好
定时器 1
立即 1
输入输出
定时器 2
立即 2
定时器 3
但我得到以下 output:
你好
定时器 1
立即 1
输入输出
立即 2
定时器 2
定时器 3
请您为我澄清一下这些行是如何逐步执行的。
这个 output 的原因是 javascript 的异步特性。
作为一些附加帮助,请查看此视频。
主持人就事件循环进行了精彩的演讲。 我认为这是一个很好的资源。
虽然这尤其适用于浏览器,但 Node.js 共享了许多方面。
首先,我应该提一下,如果您真的希望异步操作 A 以相对于异步操作 B 的特定顺序进行处理,您可能应该编写代码,这样它可以保证在不依赖确切运行的细节的情况下第一的。 但是,也就是说,我遇到了一种类型的异步操作可以“占用”事件循环并使其他类型的事件饿死的问题,如果/何时发生这种情况,了解内部真正发生的事情可能很有用。
分解到它的核心,你的问题实际上是关于为什么Immediate2
在从 I/O 回调中调度时在Timer2
之前记录,而不是从顶级代码调用时? 因此是不一致的。
这与在调用setTimeout()
和setImmediate()
时(在调度它们时)通过各种检查事件循环在其循环中所处的位置有关。 这里有些解释: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/#setimmediate-vs-settimeout 。
如果你看一下这个事件循环的简化图(来自上面的文章):
您可以看到事件循环有许多不同的部分。 setTimeout()
由图表顶部的“计时器”块提供服务。 setImmediate()
在图表底部附近的“检查”块中提供。 文件 I/O 在中间的“poll”块中提供。
因此,如果您从文件 I/O 回调(Intermediate2 和 Timer2 的情况)中同时安排setImmediate(fn1)
和setTimeout(fn2, 0)
,则事件循环处理恰好处于轮询阶段当这两个被安排时。 因此,事件循环的下一个阶段是“检查”阶段,并且setImmediate(fn1)
得到处理。 然后,在“检查”阶段和“关闭回调”阶段之后,它会循环回到“计时器”阶段,你会得到setTimeout(fn2,0)
。
另一方面,如果您从从事件循环的不同阶段运行的代码中调用这两个相同的setImmediate()
和setTimeout()
,那么计时器可能会在setImmediate()
之前首先得到处理 - 这将完全取决于在事件循环周期中执行该代码的位置。
事件循环的这种结构是为什么有些人将setImmediate()
描述为“它在 I/O 之后立即运行”,因为它位于循环中,以便在“轮询”阶段之后立即处理。 如果您正在 I/O 回调中处理某些文件 I/O,并且希望在堆栈展开后立即运行某些内容,则可以使用setImmediate()
来完成此操作。 它总是在当前 I/O 回调完成之后,但在计时器之前运行。
注意:这个简化的描述中缺少有自己特殊处理的承诺。 Promise 被认为是微任务,它们有自己的队列。 他们可以更频繁地运行。 从节点 v11 开始,它们可以在事件循环的每个阶段运行。 因此,如果您有三个准备运行的挂起计时器,并且您进入事件循环的计时器阶段并调用第一个挂起计时器的回调,并且在该计时器回调中,您解决了 promise,然后只要该计时器回调返回到系统,然后它将为已解析的 promise 提供服务。 因此,微任务(例如 promises 和process.nextTick()
)在事件循环中的每个操作之间(如果等待运行)得到服务,不仅在事件循环的阶段之间,甚至在同一阶段的未决事件之间。 您可以在此处阅读有关这些细节和节点 v11 更改的更多信息: Node v11.0.0 及更高版本中计时器和微任务的新更改。
我相信这样做是为了提高与 Promise 相关的代码的性能,因为 Promise 已成为 Node.js 架构中异步操作的核心部分,并且在该领域也有一些与标准相关的工作,以使其在不同的 JS 环境中保持一致.
这是涵盖部分内容的另一个参考:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.