【问题标题】:Node.js function not running in order. Error: Unhandled stream error in pipeNode.js 函数未按顺序运行。错误:管道中未处理的流错误
【发布时间】:2019-01-31 21:20:45
【问题描述】:

我更新了创建 CSV 文件的函数,但现在出现错误:

在上传功能中 内部/流/legacy.js:57 投掷者; // 管道中未处理的流错误。 ^

错误:ENOENT:没有这样的文件或目录,打开 'C:\Users\shiv\WebstormProjects\slackAPIProject\billingData\CSV\1548963844106output.csv'

var csvFilePath = '';
var JSONFilePath = '';
function sendBillingData(){
  var message = '';
  axios.get(url, {
    params: {
      token: myToken
    }
  }).then(function (response) {
    message = response.data;

    fields = billingDataFields;
    // saveFiles(message, fields, 'billingData/');
    saveFilesNew(message, fields, 'billingData/');
    var file = fs.createReadStream(__dirname + '/' + csvFilePath);   // <--make sure this path is correct
    console.log(__dirname + '/' + csvFilePath);
    uploadFile(file);
  })
      .catch(function (error) {
        console.log(error);
      });
} 

saveFilesNew 函数是:

function saveFilesNew(message, options, folder){
  try {
    const passedData = message;

    var relevantData='';

    if (folder == 'accessLogs/'){
      const loginsJSON = message.logins;
      relevantData = loginsJSON;
      console.log(loginsJSON);
    }
    if(folder == 'billingData/'){
      relevantData = passedData.members;
      const profile = passedData.members[0].profile;
    }

    //Save JSON to the output folder
    var date = Date.now();
    var directoryPath = folder + 'JSON/' + date + "output";
    JSONFilePath = directoryPath + '.json';
    fs.writeFileSync(JSONFilePath, JSON.stringify(message, null, 4), function(err) {
      if (err) {
        console.log(err);
      }
    });

    //parse JSON onto the CSV
    const json2csvParser = new Json2csvParser({ fields });
    const csv = json2csvParser.parse(relevantData);
    // console.log(csv);

    //function to process the CSV onto the file
    var directoryPath = folder + 'CSV/' + date + "output";
    csvFilePath = directoryPath + '.csv';

    let data = [];
    let columns = {
      real_name: 'real_name',
      display_name: 'display_name',
      email: 'email',
      account_type: 'account_type'
    };

    var id = passedData.members[0].real_name;
    console.log(id);

    console.log("messageLength is" +Object.keys(message.members).length);

    for (var i = 0; i < Object.keys(message.members).length; i++) {
      console.log("value of i is" + i);
      var display_name = passedData.members[i].profile.display_name;
      var real_name = passedData.members[i].profile.real_name_normalized;
      var email = passedData.members[i].profile.email;
      var account_type = 'undefined';
      console.log("name: " + real_name);

      if(passedData.members[i].is_owner){
        account_type = 'Org Owner';
      }
      else if(passedData.members[i].is_admin){
        account_type = 'Org Admin';
      }
      else if(passedData.members[i].is_bot){
        account_type = 'Bot'
      }
      else account_type = 'User';

      data.push([real_name, display_name, email, account_type]);
    }

    console.log(data);

    stringify(data, { header: true, columns: columns }, (err, output) => {
      if (err) throw err;
      fs.writeFileSync(csvFilePath, output, function(err) {
        console.log(output);
        if (err) {
              console.log(err);
            }
        console.log('my.csv saved.');
      });
    });

  } catch (err) {
    console.error(err);
  }
}

上传文件功能为:

function uploadFile(file){
  console.log("In upload function");
  const form = new FormData();
  form.append('token', botToken);
  form.append('channels', 'testing');
  form.append('file', file);
  axios.post('https://slack.com/api/files.upload', form, {
    headers: form.getHeaders()
  }).then(function (response) {
    var serverMessage = response.data;
    console.log(serverMessage);
  });
}

所以我认为错误是由于节点在创建文件之前尝试上传文件而引起的。我觉得这与 Node.js 的异步特性有关,但我无法理解如何纠正代码。请让我知道如何纠正这个问题,并提及对代码结构/设计的任何改进。 谢谢!

【问题讨论】:

    标签: node.js json synchronization axios export-to-csv


    【解决方案1】:

    您不必等待提供给stringify 的回调被执行,它就是您创建文件的地方。 (假设这个stringify 函数确实接受回调。)

    使用回调(您可以使用 Promise 和这些简洁的 async/await 控件使这个更简洁,但我们在这里只使用回调),它应该更像:

    function sendBillingData() {
      ...
      // this callback we'll use to know when the file writing is done, and to get the file path
      saveFilesNew(message, fields, 'billingData/', function(err, csvFilePathArgument) {
        // this we will execute when saveFilesNew calls it, not when saveFilesNew returns, see below
        uploadFile(fs.createReadStream(__dirname + '/' + csvFilePathArgument))
      });
    }
    
    // let's name this callback... "callback".
    function saveFilesNew(message, options, folder, callback) {
      ...
      var csvFilePath = ...; // local variable only instead of your global
      ...
      stringify(data, { header: true, columns: columns }, (err, output) => {
        if (err) throw err; // or return callbcack(err);
        fs.writeFile(csvFilePath , output, function(err) { // NOT writeFileSync, or no callback needed
          console.log(output);
          if (err) {
            console.log(err);
            // callback(err); may be a useful approach for error-handling at a higher level
          }
          console.log('my.csv saved.'); // yes, NOW the CSV is saved, not before this executes! Hence:
          callback(null, csvFilePath); // no error, clean process, pass the file path
    
        });
      });
      console.log("This line is executed before stringify's callback is called!");
      return; // implicitly, yes, yet still synchronous and that's why your version crashes
    }
    

    使用仅在预期事件发生时调用的回调(文件已完成写入,缓冲区/字符串已完成转换......)允许 JS 在此期间继续执行代码。它确实会继续执行代码,所以当你需要来自异步代码的数据时,你需要在执行你的代码之前告诉 JS 你需要它完成。

    另外,由于您可以在回调时传递数据(它只是一个函数),因此我可以避免依赖全局 csvFilePath。使用更高级别的变量会使事情变得单一,就像您无法将 saveFilesNew 转移到保存文件相关函数工具包的专用文件一样。

    最后,如果你的全局流程是这样的:

    function aDayAtTheOffice() {
      sendBillingData();
      getCoffee();
    }
    

    那么您无需等待结算数据处理完毕后即可开始制作咖啡。但是,如果您的老板告诉您,在结算数据之前您不能喝咖啡,那么您的流程将如下所示:

    function aDayAtTheOffice() {
      sendBillingData(function (err) {
        // if (err)  let's do nothing here: you wanted a coffee anyway, right?
        getCoffee();
      });
    }
    

    (请注意,回调作为第一个参数和数据作为第二个参数有潜在错误是一种约定,没有强制性。)

    恕我直言,您应该阅读有关 scope 的信息(参数 callback 可以在对 saveFilesNew 的调用已经完成并被遗忘的时候访问!),以及 the asynchronous nature of No... JavaScript。 ;)(抱歉,可能不是最佳链接,但它们包含有意义的关键字,然后 Google 就是您的好友、您的朋友、您的老大哥。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-28
      • 2016-02-26
      • 2017-07-20
      • 2016-10-17
      • 2017-08-30
      • 1970-01-01
      • 2023-01-25
      相关资源
      最近更新 更多