如何在循环中使用回调或异步?

时间:2018-11-20 16:37:05

标签: javascript node.js asynchronous

我搜索并阅读了有关异步函数和回调的信息。但是我有一个星期无法解决我的问题。我想按顺序在循环内执行“ 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]:回调必须是一个函数。

我对异步方法是陌生的,请提供任何帮助。

3 个答案:

答案 0 :(得分:0)

如果您使用的是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 ); 

} );

答案 1 :(得分:0)

您应该像这样使用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);
  }
});

答案 2 :(得分:-1)

您的第二个代码不提供回调函数,这就是您的错误。

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

它看起来像这样:

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查看其他答案。异步/等待很棒