2013-01-18 11 views
8

Grazie in anticipo per dare un'occhiata a questo.Node Operazione asincrona in loop con chiusura non funzionante

Ho un task asincrono all'interno di un ciclo che non funziona. Ho fatto in modo di:

  1. avvolgere la mia "chiave" variabile loop in una chiusura per evitare il classico "ultimo valore unico" problema, in cui il ciclo finisce molto prima che i compiti asincroni restituisce un valore, e solo viene visualizzato l'ultimo valore.
  2. Chiamata effettuata (errore) per completare la mia attività asincrona (secondo le FAQ di Gruntjs)
  3. Utilizzare hasOwnProperty() per assicurarsi che la chiave sia una proprietà effettiva di un oggetto e non provenga dal prototipo.
  4. Seguire il formato dell'esempio node.exec, ad eccezione dell'assegnazione del valore di exec a una variabile, che ho provato, ma non è stato di aiuto. Vedere il primo riferimento di seguito.

Questa funzione emette ... niente !? Per qualche motivo le istruzioni grunt.log.writeln non sparano nemmeno. L'attività si completa senza errori. Ho anche provato ad aggiungere un ritardo di 20 secondi, nel caso in cui lo script stesse finendo prima che venisse restituita l'attività asincrona. Stranamente, se non chiamo "done (error)", i file vengono scritti su file (quando sostituisco i writeln con le istruzioni grunt.file.write).

var done = this.async(), 
    exec = require('child_process').exec, 
    myJSON = { 
     "file1" : "C:/home/me/jquery.js", 
     "file2 " : "C:/home/me/grunt.js", 
     ... 
     "fileN" : "C:/home/me/N.js" 
    }, 
    count; 

for (var key in myJSON) { 
    if (myJSON.hasOwnProperty(key)) { 
     (function (key) { 
     exec('type "' + myJSON[key] + '"', 
      function(error, stdout, stderr) { 
      if (error) { 
       grunt.log.writeln('!!! exec error: ' + error); 
      } 
      grunt.log.writeln('stdout: ' + stdout); 
      grunt.log.writeln('stderr: ' + stderr); 
      done(error); 
      } 
     ); 
     })(key); 
    count++; 
    } 
} 

Riferimenti:

http://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback https://github.com/gruntjs/grunt/wiki/Frequently-Asked-Questions

risposta

12

done() dovrebbe essere chiamato solo quando l'intera operazione è completata, quando cioè tutti i metodi exec() s'è loro callback. Attualmente stai eseguendo la callback done a ogni iterazione. Si può facilmente raggiungere questo obiettivo utilizzando il metodo forEach nel modulo nodo async che viene fornito con grugnito (grunt.util.async (o forEachSeries se si desidera che le exec() metodi eseguiti al fine

qualcosa di simile (non testato):.

var done = this.async(); 
var exec = require('child_process').exec; 
var async = grunt.util.async; // updated 
var myJSON = { 
    "file1": "C:/home/me/jquery.js", 
    "file2": "C:/home/me/grunt.js", 
    ... 
    "fileN": "C:/home/me/N.js" 
}; 

async.forEach(Object.keys(myJSON), function(el, cb) { 
    exec('type "' + myJSON[el] + '"', function(error, stdout, stderr) { 
     if (error) { 
      grunt.warn('!!! exec error: ' + error) 
      return cb(error); 
     } 
     grunt.log.writeln('stdout: ' + stdout); 
     grunt.log.writeln('stderr: ' + stderr); 
     cb(); 
    } 
); 
}, function(error) { 
    done(!error); 
}); 
+0

tyvm. Le FAQ mi hanno portato a credere che done() doveva essere invocato per _each_ operazione asych all'interno di un'attività.E 'stato un grande aiuto, ho apprezzato il tuo tempo. :). – user1354017

+0

Quindi, il take-away qui è che le utility grunt.utils.async siano preferite per lavorare con compiti asincroni - al contrario di creare manualmente chiusure, ecc., corretto? – user1354017

+0

Questo è il cor retto, ma non solo per grugnito. È inestimabile quando si lavora in Node.js in generale. https://github.com/caolan/async –

Problemi correlati