【问题标题】:Synchronous execution for node.js program using 'readline'使用“readline”同步执行 node.js 程序
【发布时间】:2017-01-08 16:37:12
【问题描述】:

我在让 node 的异步特性与我合作时遇到了一些问题,并且在经过数小时的回调和谷歌搜索之后;我终于转向你们了。

我有一个程序需要使用 node 的 readline 模块从文件中读取行。该文件包含传递给我的节点程序中定义的一些异步函数的数据。一旦所有数据被成功读取和处理后,需要将这些数据解析成JSON格式,然后输出。

我的问题是,当我调用:readLine.on('close', function() { ...... } 时,这是在异步函数完成运行之前运行的,因此我没有任何输出,但程序继续运行异步函数。

我创建了一个简单的函数框架,可以更清楚地解释我的情况:

function firstAsyncFunc(dataFromFile) {
   //do something asynchronously

   return processedData;
}


function secondAsyncFunc(dataFromFile) {
  //do something else asynchronously

  return processedData;
}


//create readline 
var lineReader = require('readline').createInterface({
  input: require('fs').createReadStream('data.txt')
});


//array to hold all the data processed
var totalDataStorage; 


//read file 
lineReader.on('line', function(line) {

  var processedData = firstAsyncFunction(line);
  var moreProcessedData = secondAsyncFunction(line);


  //store processed data and concatenate into one array
  var tempDataStorage = [{ 'first': processedData, 'second': moreProcessedData }]
  totalDataStorage = totalDataStorage.concat(tempDataStorage);

}).on('close', function() {

  var JSONString = JSON.stringify(... //create JSON for totalDataStorage ...);
  console.log(JSONString); //DOESN'T OUTPUT ANYTHING!

});

我尝试向 first/secondAsynFunction 添加回调,我尝试使程序的读取和解析位分开函数,并创建回调以便仅在读取完成时调用解析,但这些解决方案都没有似乎正在工作,我真的很挣扎 - 所以任何帮助将不胜感激。

谢谢!

编辑:data.txt 文件的格式为

IPData1 DataCenter1
IPData2 DataCenter2
...
IPDataN DataCenterN

我使用 str.split(" ") 来获取各自的值,然后适当地传递它们。 IPData 是数字,DataCenter 是字符串

【问题讨论】:

  • 可以分享一下data.txt文件吗?我相信我可以回答你
  • @JaromandaX 再次查看 OP 的代码。它是一个数组,而不是字符串。
  • data.txt 文件的格式为:IPData, DataCentre。在实际程序中,我使用 str.split(" ") 来拆分两个值,然后将它们传递给必要的函数。 IPData 是一个数字,DataCentre 值是一个字符串。希望这会有所帮助
  • @OliverOstach 您的代码中有很多错误。您需要意识到,每次调用异步函数时,它都不会返回值,并且您还需要传递一个回调函数。你的行var processedData = firstAsyncFunction(line); 完全没有意义。此外,使用fs.readFile 可以在几行中轻松完成。
  • 啊我忘了提到异步函数返回值!准确地说是字符串值!我现在会编辑它

标签: javascript node.js asynchronous readline synchronous


【解决方案1】:

异步函数不返回值,但您必须将回调函数传递给它。你的线路

var processedData = firstAsyncFunction(line);

根本没有意义。如果您的data.txt 文件看起来像这样

IPData1 DataCenter1
IPData2 DataCenter2
IPData3 DataCenter3

您可以按如下方式读取数据

var fs = require('fs');
var rl = require('readline').createInterface({
  input: fs.createReadStream('data.txt')
});
var arr = [];

rl.on('line', a => {
  a = a.split(' ');
  arr.push({
    first: a[0],
    second: a[1]
  });
}).on('close', () => {
  console.log(JSON.stringify(arr, null, 2));
});

它会记录

[
  {
    "first": "IPData1",
    "second": "DataCenter1"
  },
  {
    "first": "IPData2",
    "second": "DataCenter2"
  },
  {
    "first": "IPData3",
    "second": "DataCenter3"
  }
]

【讨论】:

  • 感谢您的帮助,但不幸的是,这不起作用。我已经注册了一个回调函数来“返回”异步函数的结果,然后从lineReader.on('line', ...) 中适当地调用它们,但我仍然遇到.on('close') 的相同问题,正在运行 BEFORE 异步函数已完成并返回结果..(这是我的问题,我已经能够验证我做的其他所有事情都是正确的!)
  • @OliverOstach 您根本无法理解异步函数的工作原理。根据定义,异步函数 CANNOT 返回一个值,所以停止调用它异步。如果它返回一个值,那么它必须onClose 事件被触发之前运行,因为这是v8 引擎的工作方式。你怎么觉得我的回答行不通?你试过了吗?复制粘贴它以确保它正常工作。
【解决方案2】:

我更改了以下内容及其在本地工作。

  1. 使用承诺让您的生活更轻松。
  2. 删除 .close,因为您没有在接口中定义输出。

当发生以下情况之一时,会发出“关闭”事件:

  1. 调用了 rl.close() 方法,并且 readline.Interface 实例放弃了对输入和输出流的控制;
  2. 输入流接收其“结束”事件;
  3. 输入流接收 -D 以表示传输结束 (EOT);
  4. 输入流接收 -C 以发出 SIGINT 信号,并且 readline.Interface 实例上没有注册 SIGINT 事件侦听器。
function firstAsyncFunc(dataFromFile) {
  return new Promise(function(resolve, reject) {
    //do something asynchronously
    resolve(result);
  })
}

function secondAsyncFunc(dataFromFile) {
  return new Promise(function(resolve, reject) {
    //do something asynchronously
    resolve(result);
  })
}

//create readline 
var lineReader = require('readline').createInterface({
  input: require('fs').createReadStream('data.txt')
});

//array to hold all the data processed
var totalDataStorage;

//read file 
lineReader.on('line', function(line) {
  Promise.all([
      firstAsyncFunc(line),
      secondAsyncFunc(line)
    ])
    .then(function(results) {
      var tempDataStorage = [{
        'first': results[0],
        'second': results[1]
      }];
      // i'd use push instead of concat
      totalDataStorage = totalDataStorage.concat(tempDataStorage);
    });
})

【讨论】:

  • 这似乎可以工作,但我似乎无法弄清楚我将在哪里记录数据,以便所有异步函数都将由记录阶段执行
猜你喜欢
  • 2017-06-24
  • 1970-01-01
  • 2011-05-25
  • 1970-01-01
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多