Je recherche et lis les fonctions asynchrones et les rappels. Mais je n'ai pas pu résoudre mon problème pendant une semaine. Je veux faire la boucle intérieure de «fs readfile» avec ordre. J'essaye ce qui suit mais je ne réussis pas.

// 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
  });

J'essaye aussi d'une autre manière:

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);
   }
});

Sur ce qui précède, j'obtiens une erreur de: TypeError [ERR_INVALID_CALLBACK]: Le rappel doit être une fonction.

Je suis nouveau dans les méthodes asynchrones.

0
wzwd 20 nov. 2018 à 19:37

3 réponses

Meilleure réponse

Si vous utilisez Node v10 ou supérieur, vous pouvez utiliser le fs promet l'API et asynchrone / attend.

Pour lire les fichiers en série:

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 ); 

} );

Ou pour les lire en parallèle:

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 ); 

} );
0
Paul 20 nov. 2018 à 16:44

Vous devez utiliser la syntaxe ES2017 async/await comme celle-ci.

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);
  }
});
0
Fernando Carvajal 6 déc. 2018 à 19:24

Votre deuxième code ne fournit pas de fonction de rappel, c'est votre erreur.

Votre premier code, vous essayez de travailler avec des rappels, vous devrez donc suivre votre code imbriqué dans le rappel, c'est ce qu'on appelle l'enfer de rappel

Cela ressemblerait à ceci:

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)
      }            
     });
  });

Si vous prévoyez d'utiliser le nœud 10, je vous recommande de regarder l'autre réponse avec Promise.all. L'async / attente est génial

-1
iagowp 20 nov. 2018 à 17:27