【问题标题】:How to use callback or Async in for loop?如何在 for 循环中使用回调或异步?
【发布时间】:2018-11-20 16:37:05
【问题描述】:

我搜索并阅读了有关异步函数和回调的信息。但我无法解决我的问题一个星期。我想按顺序在循环内执行“fs readfile”。我尝试了以下方法,但没有成功。

// on the code below, console.log print the value in random order and 'storedata' is empity.
// my goal is to do readfile in loop orderly and store the value

router.get("/files/readfiles", function(req,res){
  var storedata= []; 
  var filenames= ["file1","file2","file3","file4"]; 

  for (var i=0; i< filenames.length; i++){      
    fs.readFile('views/allfiles/'+ filenames[i] +'.ejs','utf8',function (err, data) {
      if (err) throw err;  
      storedata.push(data);         
      console.log(data);         
    });
    console.log(storedata); // this returns empty array
  });

我也尝试了另一种方式:

router.get("/files/readfiles", function(req,res){
var filenames= ["file1","file2","file3","file4"];   

filenames.forEach(readfiles);

function readfiles(value) {
  var dataread =  fs.readFile('views/allfiles/'+ value +'.ejs','utf8')

    console.log (dataread);
   }
});

在上面的尝试中我得到一个错误:TypeError [ERR_INVALID_CALLBACK]:回调必须是一个函数。

我是异步方法的新手,请提供任何帮助。

【问题讨论】:

  • 您必须使用同步版本或Promise.all。无论哪种方式,您都需要了解异步 的含义,当然console.log(storedata) 会记录一个空数组,因为 IO 在运行时尚未完成。如果您使用回调,您只能访问回调中的数据。
  • 你想要的结果到底是什么?尽可能快地浏览它,或者一次读取一个文件。
  • @Kevin 我想在循环内执行 fs 读取文件(按顺序读取多个文件)然后存储值以使用它。正如我在问题中所写的那样,这就是我想要的。
  • @wzwd 是的,我明白这一点,但由于读取文件的异步特性,您有两种不同的方式来做。您尚未指定首选哪一个。

标签: javascript node.js asynchronous


【解决方案1】:

如果您使用的是 Node v10 或更高版本,则可以使用 fs promises API 和 async/await。

连续读取文件:

router.get( "/files/readfiles", async function( req, res ) {
  const storedata = [ ]; 
  const filenames = [ "file1", "file2" , "file3", "file4" ]; 

  for (let i = 0; i < filenames.length; i++ ) {      
    const data = await fs.promises.readFile( 'views/allfiles/'+ filenames[i] +'.ejs', { encoding: 'utf8' } ); 
    storedata.push( data );         
  }

  console.log( storedata ); 

} );

或并行阅读:

router.get( "/files/readfiles", async function( req, res ) {
  const promises = [ ]; 
  const filenames = [ "file1", "file2", "file3", "file4" ]; 

  for (let i = 0; i < filenames.length; i++ ) {      
    const promise = fs.promises.readFile( 'views/allfiles/'+ filenames[i] +'.ejs', { encoding: 'utf8' } ); 
    promises.push( promise );         
  }

  const storedata = await Promise.all( promises );

  console.log( storedata ); 

} );

【讨论】:

  • 在第一种方法中我得到:'解析错误:意外的令牌 fs'。我无法修改此行。在第二种方法中,我得到以下结果:` [ Promise { }, Promise { }, Promise { }, Promise { }, Promise { },]` ( node:3575) ExperimentalWarning: fs.promises API 是实验性的
  • @wzwd 听起来你没有将async 关键字放在function 前面。
  • ExperimentalWarning 应该在那里,但它只是打印到 stderr 并且不应该影响您的程序。
  • 是的,我忘了在函数上添加异步。它完美地工作。谢谢
【解决方案2】:

你应该像这样使用 ES2017 async/await 语法。

router.get("/files/readfiles", async function(req, res){
  var storedata= []; 
  var filenames= ["file1","file2","file3","file4"]; 

  for (var i=0; i< filenames.length; i++){  
    await new Promise((resolve, reject) => {    
        fs.readFile('views/allfiles/'+ filenames[i] +'.ejs','utf8',function (err, data) {
          if (err) return reject( err )
          storedata.push(data);
          resolve();               
        });
    })
    console.log(storedata);
  }
});

【讨论】:

    【解决方案3】:

    你的第二个代码没有提供回调函数,那是你的错误。

    您的第一个代码,您正在尝试使用回调,因此您需要遵循嵌套在回调中的代码,这就是所谓的回调地狱

    看起来像这样:

    router.get("/files/readfiles", function(req,res){
      var storedata= []; 
      var filenames= ["file1","file2","file3","file4"]; 
    
      for (let i = 0; i< filenames.length; i++){      
        fs.readFile('views/allfiles/'+ filenames[i] +'.ejs','utf8',function (err, data) {
          if (err) throw err;  
          storedata[i] = data;
    
          if (storedata.length === filenames.length) {
            console.log(storedata);
            // do stuff you want, like:
            res.send(storedata)
          }            
         });
      });
    

    如果您打算使用节点 10,我建议您使用 Promise.all 查看其他答案。异步/等待很棒

    【讨论】:

    • 感谢它正在工作,我需要阅读更多关于回调、异步/等待、承诺的信息。我正在使用 Node v10.6.0,但这次我不知道如何使用 Promise 和 Async。可能如果你有一些学习链接我会关注它
    猜你喜欢
    • 2011-11-08
    • 2023-03-19
    • 2016-12-31
    • 2011-12-03
    • 2018-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-16
    相关资源
    最近更新 更多