Async: Obtenir une nouvelle erreur en utilisant Async avec le nœud 6.2.2 "Rappel déjà appelé"

Créé le 27 juin 2016  ·  12Commentaires  ·  Source: caolan/async

Quelle version d'async utilises-tu ?

3.9.5

Dans quel environnement le problème s'est-il produit (version du nœud/version du navigateur)

Nœud 6.2.2 et 5.0.71.52

Qu'est-ce que tu as fait?

Cette application

var fs = require('fs'),
    async = require('async'),
    _dir = './data/';

var writeStream = fs.createWriteStream('./log.txt',
      {'flags' : 'a',
       'encoding' : 'utf8',
       'mode' : 0666});

async.waterfall([
   function readDir(callback) {
      fs.readdir(_dir, function(err, files) {
         callback(err,files);
      });
   },
   function loopFiles(files, callback) {
      files.forEach(function (name) {
         callback (null, name);
      });
   },

   function checkFile(file, callback) {
      fs.stat(_dir + file, function(err, stats) {
         callback(err, stats, file);
      });
   },
   function readData(stats, file, callback) {
      if (stats.isFile())
         fs.readFile(_dir + file, 'utf8', function(err, data){
           callback(err,file,data);
       });
   },
   function modify(file, text, callback) {
      var adjdata=text.replace(/somecompany\.com/g,'burningbird.net');
      callback(null, file, adjdata);
   },
   function writeData(file, text, callback) {
       fs.writeFile(_dir + file, text, function(err) {
          callback(err,file);
       });
   },

   function logChange(file, callback) {
       writeStream.write('changed ' + file + '\n', 'utf8',
                       function(err) {
          callback(err);
      });
   }
], function (err) {
         if (err) {
            console.log(err.message);
         } else {
            console.log('modified files');
         }
});

Que vous attendiez-vous à ce qu'il se passe?

Que je n'aurais pas d'erreur

Quel a été le résultat réel ?

Je suis en train

/home/examples/public_html/learnnode2-examples/chap3/node_modules/async/dist/async.js:837
if (fn === null) throw new Error("Le rappel a déjà été appelé.");
^

Erreur : Le rappel a déjà été appelé.

La fonction de rappel dans la section suivante du code

fonction loopFiles(fichiers, rappel) {
files.forEach(fonction (nom) {
rappel (null, nom);
});
},

Est perdu au deuxième run.

J'ai exécuté ce code avec succès sur plusieurs versions de Node. Je crois que j'ai testé cela lors de la première sortie de Node 6.

Dans la deuxième itération, la fonction n'est pas nulle, mais quelque chose se passe dans le code asynchrone entraînant cette erreur.

question

Tous les 12 commentaires

Parce que vous avez rappelé plusieurs fois ici :

function loopFiles(files, callback) {
    files.forEach(function(name) {
        callback(null, name);
    });
},

Veuillez utiliser async.forEach pour ce cas.

Intéressant. Je n'ai eu aucun problème avec les versions précédentes de Node et, en fait, je viens de l'exécuter avec succès dans Node 6.0.0 sur ma machine Windows.

Ainsi, quelque chose a changé entre 6.0.0 et 6.2.2, ce qui provoque la rupture d'Async avec l'utilisation de forEach intégré.

Juste pour info, async.forEach ne fonctionne pas. Il ne plante pas, mais il ne fonctionne pas.

   function loopFiles(files, callback) {
      async.forEach(files, function (name, callback) {
         callback (null, name);
      });
   },

Et franchement, je ne suis pas sûr que ce soit le forEach qui pose problème. Si je ne l'utilise pas correctement, faites-le moi savoir.

D'accord, j'abandonne.

J'ai mis à jour ma machine Windows vers 6.2.2, et ce code fonctionne. Mais cela ne fonctionne pas sur ma machine Linux. Les deux sont construits sur le même moteur V8. Les deux utilisent la même version d'Async. Les deux ont les mêmes répertoires de fichiers d'exemple.

Sous Linux, une erreur est levée. Sous Windows, non.

@shelleyp votre cascade est mal structurée pour plusieurs fichiers. Je pense que vous voulez le séparer en deux cascades ou que chaque étape attend un tableau.

La raison pour laquelle votre modification de async.forEach n'a pas fonctionné est que vous n'appelez pas le rappel loopFiles . Cette fonction ne fait pas ce que vous voulez de toute façon, si vous voulez seulement traiter le premier fichier, changez loopFiles en (files, callback) => callback(null, files[0]) sinon vous aurez besoin d'avoir checkFiles , readData et modify attendent des tableaux (ou créent une deuxième cascade)

Je ne vais pas corriger tout votre code, mais voici comment je changerais votre fonction checkFiles

async.waterfall([
   function readDir(callback) {
      fs.readdir(_dir, callback);
   },

   function checkFile(files, callback) {
      async.map(files, (file, cb) => {
         fs.stat(_dir + file, function(err, stats) {
            cb(err, {stat: stats, file: file});
         });
      }, (err, stats) => {
         callback(err, stats);
      });
   },

....

C'est très bien.

Sachez simplement que cela a fonctionné jusqu'au 6.2.2, donc tout ce qui a fait que mon code ne fonctionne pas peut empêcher le code d'autres personnes de fonctionner.

Bizarre, la seule chose qui devrait faire fonctionner ce code est que les listes readdir
un fichier (il est également cassé pour 0 fichiers).

Cela vous dérange-t-il de vérifier la sortie de readdir dans les deux versions de nod
Le 27 juin 2016 à 17h55, "Shelley Powers" [email protected] a écrit :

C'est très bien.

Sachez simplement que cela a fonctionné jusqu'au 6.2.2, donc peu importe ce qui a empêché mon code de
work peut empêcher le code d'autrui de fonctionner.

-
Vous recevez ceci parce que vous avez modifié l'état ouvert/fermé.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/caolan/async/issues/1199#issuecomment -228887866, ou couper le son
le fil
https://github.com/notifications/unsubscribe/ADUIEAfvkwCmdjmkIZIjipFGYgPQ6SzYks5qQEbpgaJpZM4I_Nsg
.

Ce code a toujours fonctionné avec plusieurs fichiers. Eh bien, jusqu'au 6.2.2 sur Linux.

Mais je viens de vérifier sur Windows. Oui, j'ai travaillé avec quatre fichiers.

La sortie de readdir est [ 'data1.txt', 'data2.txt', 'data3.txt', 'data4.txt' ]

l'entrée dans loopFiles est la même.

À ce moment-là, avec forEach, chaque rappel reçoit un nom de fichier individuel.

Si j'avais déjà rencontré un mur de briques avec le tableau, je n'aurais pas utilisé cette approche. Mais cela a toujours fonctionné.

Pas grave, je peux toujours mettre à jour le code pour supprimer la gestion du tableau. Le vrai problème est que cela fonctionne dans un environnement mais pas dans un autre. Pourtant, Node, V8 et Async sont les mêmes versions.

Je viens d'exécuter du code légèrement modifié dans Ubuntu 16.04 dans les nœuds 6.0.0 et 6.2.2. Dans les deux cas j'ai le même résultat :

  • data1.txt, rappel pour le premier élément (data1.txt)
  • Erreur : le rappel a déjà été appelé

Script modifié :

var fs = require('fs'),
    async = require('async'),
    _dir = './data/';

async.waterfall([
   function readDir(callback) {
      fs.readdir(_dir, callback);
   },
   function loopFiles(files, callback) {
      files.forEach(function (name) {
         callback (null, name);
      });
   },
   console.log.bind(console)
], console.error)
$ ls data
> data1.txt  data2.txt

Mais vous ne l'avez pas essayé sous Windows.

Bien sûr, je le ferme car ce n'est pas un problème asynchrone.

Le lundi 27 juin 2016 à 20h20, Shelley Powers [email protected]
a écrit:

Mais vous ne l'avez pas essayé sous Windows.

-
Vous recevez ceci parce que vous avez modifié l'état ouvert/fermé.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/caolan/async/issues/1199#issuecomment -228914233, ou couper le son
le fil
https://github.com/notifications/unsubscribe/ADUIEDNwRmcEjcAnVmSCHBBIHvdM6DL3ks5qQGiwgaJpZM4I_Nsg
.

Cette page vous a été utile?
0 / 5 - 0 notes