Node.JS中的事件循环如何可预测

BSJ

如果您观察到像这样的简单客户端JS ,很直观,如果遇到setTimeouts,则时间长度(在本示例中为0 ms)确定JS运行时实际上将其添加到队列后的时间间隔,如所解释的在这里

但是,在Node.JS中,如果我有一些基本上是异步的api调用(例如fs.readFile()),并且如果我有一个简单的setTimeout,则在同一代码库中,我的理解是事件循环将开始读取文件,如果已被读取,它将继续执行并排队,以便一旦主节点线程不执行任何顺序操作时就可以触发适当的回调。我的问题是,仅在特定超时仍然保持之后(与类客户端JS相反),“添加setTimeout回调”这一概念是否存在?具体来说,这是一个示例:

const fs = require('fs');
// Set timeout for 2 secs
setTimeout(function() { 
  console.log('Timeout ran at ' + new Date().toTimeString()); 
}, 2000);
// Read some file
fs.readFile('sampleFile.txt', function(err, data) {
   if(err) {
     throw err;
   }
   console.log(data.toString() + " " + new Date().toTimeString();
}
var start = new Date();
console.log('Enter loop at: '+start.toTimeString());
// run a loop for 4 seconds
var i = 0;
// increment i while (current time < start time + 4000 ms)
while(new Date().getTime() < start.getTime() + 4000) {
  i++;
}
console.log('Exit loop at: ' +new Date().toTimeString() +'. Ran '+i+' iterations.');

我为此得到的输出是:

在以下时间进入循环:GMT-0700(PDT)18:22:14(退出)在以下时间退出循环:GMT-0700(PDT)18:22:18。跑了33980131次迭代。超时在格林尼治标准时间07:00(PDT)18:22:18运行SampleFileContents格林尼治标准时间07:00(PDT)18:22:18

这是否意味着在完全读取文件之前,将setTimeout回调+消息以某种方式放置在事件循环队列中?这告诉我3件事情中的1件:将setTimeout回调+消息放置在队列中,准备在2秒和下一个可用滴答之后触发。或实际读取sampleFile.txt的时间超过2秒。或快速读取了sampleFile.txt,但是由于某种原因,它没有放在事件循环队列中的setTimeout之前。

我是否使用正确的思维模式来考虑这个问题?我试图更深入地了解节点的内部结构,而不必深入研究libuv / libeio C代码。我尝试过尝试超时,并且有趣的是,当我将超时设置为大于4000毫秒时,似乎在我的输出中,我总是打印出sampleFileContents,然后才实际打印超时时间。

用户名

有一个陷阱。以下代码行是同步的和阻塞的。

// increment i while (current time < start time + 4000 ms)
while(new Date().getTime() < start.getTime() + 4000) {
  i++;
}

这意味着事件循环被它劫持了,并且永远无法像您期望的那样起作用。

文件settmeout读取之前打印可能意味着在循环开始之前的时间点已经设置了计时器,但是尚未添加文件读取事件。我添加了更多代码来验证这个想法。

var readStream = fs.createReadStream('sampleFile.txt');

  readStream.on('open', function () {
    console.log('Read started ' + new Date().toTimeString());
  });

  readStream.on('data', function(data) {
  });

  readStream.on('end', function(err) {
   console.log('Read end ' + new Date().toTimeString());
  });   

setTimeout(function() {
  console.log('Timeout ran at ' + new Date().toTimeString());
}, 2000);

var start = new Date();
console.log('Enter loop at: '+start.toTimeString());

var i = 0;
while(new Date().getTime() < start.getTime() + 4000) {
  i++;
}

console.log('Exit loop at: ' +new Date().toTimeString() +'. Ran '+i+' times.');

输出为:

Enter loop at: 22:54:01 GMT+0530 (IST)
Exit loop at: 22:54:05 GMT+0530 (IST). Ran 34893551 times.
Timeout ran at 22:54:05 GMT+0530 (IST)
Read started 22:54:05 GMT+0530 (IST)
Read end 22:54:05 GMT+0530 (IST)

这证明了我的理论,即它们从未同时运行。至于发生这种情况的原因,我相信fs事件至少需要一个滴答声才能排队并正确发送。但是超时会立即添加。由于您在添加文件读取事件之前锁定了事件循环,因此在循环结束后,它在超时处理程序之后排队。

您可以尝试运行没有循环的代码,输出将是

Enter loop at: 22:57:15 GMT+0530 (IST)
Exit loop at: 22:57:15 GMT+0530 (IST). Ran 0 iterations.
 22:57:15 GMT+0530 (IST)
Timeout ran at 22:57:17 GMT+0530 (IST)

如果读取先完成。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Node.JS中的事件循环如何可预测

来自分类Dev

Node.js事件循环

来自分类Dev

如何在Node.js中检测和测量事件循环阻塞?

来自分类Dev

如何在node.js中创建一个可中断的循环

来自分类Dev

如何从Node.js代码访问事件循环?

来自分类Dev

如何突破Node.js中的for循环

来自分类Dev

如何打破 node.js 中的循环?

来自分类Dev

Node JS:如何承诺 For 循环

来自分类Dev

如何从Node.js中的构造函数发出/捕获事件?

来自分类Dev

如何在node.js中编写可重用函数?

来自分类Dev

检查node.js事件循环中的事件

来自分类Dev

Node.js EventEmitter事件不共享事件循环

来自分类Dev

如何处理node.js中的循环?

来自分类Dev

在Node.js中完成for循环后如何运行函数?

来自分类Dev

如何在回调函数Node JS中打破for循环

来自分类Dev

如何在Node.JS中编写异步While循环

来自分类Dev

如何在Node.js / Javascript中停止无限循环

来自分类Dev

如何在回调函数Node JS中打破for循环

来自分类Dev

如何从Node.js中的循环添加MySQL查询结果?

来自分类Dev

如何在async.waterfall Node.js中循环

来自分类Dev

如何循环遍历 Node.js 中的 GraphTraversal 对象?

来自分类Dev

Node.JS中的单线程事件循环与多线程非阻塞工作者

来自分类Dev

对事件循环,多线程,在Node.js中执行readFile()的顺序有疑问吗?

来自分类Dev

Node.JS中的单线程事件循环与多线程非阻塞工作者

来自分类Dev

Node JS 同步事件

来自分类Dev

Node.js中的子事件顺序

来自分类Dev

同步node.js中的查询(或事件)

来自分类Dev

如何在node.js事件监听器中获取事件名称?

来自分类Dev

如何在node.js事件侦听器中获取事件名称?

Related 相关文章

热门标签

归档