Async: Obtendo um novo erro ao usar o Async com o Node 6.2.2 "Callback já chamado"

Criado em 27 jun. 2016  ·  12Comentários  ·  Fonte: caolan/async

Qual versão do assíncrono você está usando?

3.9.5

Em qual ambiente o problema ocorreu (versão do nó / versão do navegador)

Nó 6.2.2 e 5.0.71.52

O que você fez?

Este app

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

O que você esperava que fosse acontecer?

Que eu não receberia um erro

Qual foi o resultado real?

Estou entendendo

/home/examples/public_html/learnnode2-examples/chap3/node_modules/async/dist/async.js:837
if (fn === null) lança um novo Error ("Callback já foi chamado.");
^

Erro: o retorno de chamada já foi realizado.

A função de retorno de chamada na seção seguinte do código

function loopFiles (arquivos, retorno de chamada) {
files.forEach (function (name) {
retorno de chamada (nulo, nome);
});
},

Está perdido na segunda corrida.

Executei esse código com êxito em várias versões do Node. Acredito que testei isso quando o Nó 6 foi lançado pela primeira vez.

Na segunda iteração, a função não é nula, mas algo está acontecendo no código Async resultando neste erro.

question

Todos 12 comentários

Porque você ligou de retorno muitas vezes aqui:

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

Use async.forEach para este caso.

Interessante. Não tive problemas com versões anteriores do Node e, na verdade, apenas executei isso com êxito no Node 6.0.0 em minha máquina Windows.

Portanto, algo mudou entre 6.0.0 e 6.2.2 que faz com que o Async interrompa com o uso do forEach integrado.

Apenas um FYI, async.forEach não funciona. Não trava, mas não funciona.

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

E, francamente, não tenho certeza se o forEach está causando o problema. Se eu estiver usando incorretamente, avise-me.

Ok eu desisto.

Atualizei minha máquina Windows para 6.2.2 e este código funciona. Mas não funciona na minha máquina Linux. Ambos são construídos no mesmo motor V8. Ambos estão usando a mesma versão do Async. Ambos têm os mesmos diretórios de arquivo de exemplo.

No Linux, o erro é lançado. No Windows, não.

@shelleyp sua cascata está estruturada incorretamente para vários arquivos. Acho que você quer separá-lo em duas cachoeiras ou fazer com que cada etapa espere um array.

A razão pela qual sua async.forEach alteração não funcionou é porque você não está chamando o retorno de chamada loopFiles . Essa função não está fazendo o que você deseja de qualquer maneira, se você só deseja processar o primeiroFile, altere loopFiles para (files, callback) => callback(null, files[0]) caso contrário, você precisará ter checkFiles , readData e modify esperam matrizes (ou crie uma segunda cascata)

Não vou consertar todo o seu código, mas é assim que eu mudaria sua função 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);
      });
   },

....

Isso é bom.

Apenas saiba que isso funcionou até 6.2.2, então o que quer que tenha feito meu código não funcionar pode fazer com que o código de outras pessoas não funcione.

Estranho, a única coisa que deve fazer esse código funcionar é se o readdir lista
um arquivo (também está quebrado para 0 arquivos).

Você se importa em verificar a saída de readdir em ambas as versões do nod
Em 27 de junho de 2016, 17:55, "Shelley Powers" [email protected] escreveu:

Isso é bom.

Apenas saiba que isso funcionou até 6.2.2, então tudo o que fez com que meu código não
trabalho pode fazer com que o código de outras pessoas não funcione.

-
Você está recebendo isso porque modificou o estado abrir / fechar.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/caolan/async/issues/1199#issuecomment -228887866 ou mudo
o segmento
https://github.com/notifications/unsubscribe/ADUIEAfvkwCmdjmkIZIjipFGYgPQ6SzYks5qQEbpgaJpZM4I_Nsg
.

Este código sempre funcionou com vários arquivos. Bem, até 6.2.2 no Linux.

Mas apenas verifiquei no Windows. Sim, trabalhei com quatro arquivos.

A saída de readdir é ['data1.txt', 'data2.txt', 'data3.txt', 'data4.txt']

a entrada para loopFiles é a mesma.

Nesse momento, com forEach, cada retorno de chamada obtém um nome de arquivo individual.

Se eu já tivesse batido em uma parede de tijolos com o array, não teria usado essa abordagem. Mas sempre funcionou.

Não é nada demais, sempre posso atualizar o código para remover o manuseio do array. O verdadeiro problema é que funciona em um ambiente, mas não em outro. No entanto, Node, V8 e Async são as mesmas versões.

Acabei de executar um código ligeiramente modificado no Ubuntu 16.04 no nó 6.0.0 e 6.2.2. Em ambos os casos, obtive a mesma saída:

  • data1.txt, retorno de chamada para o primeiro item (data1.txt)
  • Erro: o retorno de chamada já foi chamado

Script modificado:

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

Mas você não experimentou no Windows.

Claro, estou fechando-o porque não é um problema assíncrono.

Na segunda-feira, 27 de junho de 2016 às 20h20, Shelley Powers [email protected]
escreveu:

Mas você não experimentou no Windows.

-
Você está recebendo isso porque modificou o estado abrir / fechar.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/caolan/async/issues/1199#issuecomment -228914233 ou mudo
o segmento
https://github.com/notifications/unsubscribe/ADUIEDNwRmcEjcAnVmSCHBBIHvdM6DL3ks5qQGiwgaJpZM4I_Nsg
.

Esta página foi útil?
0 / 5 - 0 avaliações