Async: Получение новой ошибки при использовании Async с узлом 6.2.2 «Обратный вызов уже вызван»

Созданный на 27 июн. 2016  ·  12Комментарии  ·  Источник: caolan/async

Какую версию async вы используете?

3.9.5

В какой среде возникла проблема (версия узла / версия браузера)

Узел 6.2.2 и 5.0.71.52

Что ты сделал?

Это приложение

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

Чего вы ожидали?

Что я не получу ошибку

Каков был реальный результат?

Я получаю

/home/examples/public_html/learnnode2-examples/chap3/node_modules/async/dist/async.js:837
if (fn === null) throw new Error («Обратный вызов уже был вызван.»);
^

Ошибка: обратный вызов уже был вызван.

Функция обратного вызова в следующем разделе кода

function loopFiles (файлы, обратный вызов) {
files.forEach (функция (имя) {
обратный вызов (ноль, имя);
});
},

Теряется на втором заходе.

Я успешно запустил этот код в нескольких версиях Node. Думаю, я тестировал это, когда впервые был выпущен Node 6.

Во второй итерации функция не равна нулю, но что-то происходит в асинхронном коде, что приводит к этой ошибке.

question

Все 12 Комментарий

Потому что вы здесь много раз вызывали обратный вызов:

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

В этом случае используйте async.forEach.

Интересно. У меня не было проблем с предыдущими версиями Node, и на самом деле я просто успешно выполнил это в Node 6.0.0 на моем компьютере с Windows.

Итак, что-то изменилось между 6.0.0 и 6.2.2, что вызывает сбой Async с использованием встроенного forEach.

Просто к сведению, async.forEach не работает. Не вылетает, но и не работает.

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

И, честно говоря, я не уверен, что проблема в forEach. Если я использую неправильно, дайте мне знать.

Хорошо, я сдаюсь.

Я обновил свой компьютер с Windows до версии 6.2.2, и этот код работает. Но на моей Linux-машине это не работает. Оба построены на одном и том же двигателе V8. Оба используют одну и ту же версию Async. Оба имеют одинаковые каталоги файлов примеров.

В Linux выдается ошибка. В Windows нет.

@shelleyp ваш водопад неправильно структурирован для нескольких файлов. Я думаю, вы хотите разделить его на два водопада или сделать так, чтобы каждый шаг ожидал массива.

Причина, по которой ваше изменение async.forEach не сработало, заключается в том, что вы не вызываете обратный вызов loopFiles . Эта функция в любом случае не выполняет то, что вы хотите, если вы хотите обработать только firstFile change loopFiles до (files, callback) => callback(null, files[0]) противном случае вам понадобится checkFiles , readData и modify ожидают массивы (или создают второй водопад)

Я не собираюсь исправлять весь ваш код, но вот как я бы изменил вашу функцию 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);
      });
   },

....

Хорошо.

Просто знайте, что это работало до 6.2.2, поэтому все, что заставляло мой код не работать, может привести к тому, что код других людей не будет работать.

Странно, единственное, что должно заставить этот код работать, - это если список readdir
один файл (тоже битый на 0 файлов).

Вы не возражаете, чтобы дважды проверить вывод readdir в обеих версиях nod
27 июня 2016 г. в 17:55 «Шелли Пауэрс» [email protected] написала:

Хорошо.

Просто знайте, что это работало до 6.2.2, поэтому, что бы ни заставляло мой код не
работа может привести к тому, что чужой код не будет работать.

-
Вы получаете это, потому что изменили состояние открытия / закрытия.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/caolan/async/issues/1199#issuecomment -228887866 или отключить звук
нить
https://github.com/notifications/unsubscribe/ADUIEAfvkwCmdjmkIZIjipFGYgPQ6SzYks5qQEbpgaJpZM4I_Nsg
.

Этот код всегда работал с несколькими файлами. Ну, до 6.2.2 в Linux.

Но только что проверил на винде. Ага, работал с четырьмя файлами.

Вывод readdir: ['data1.txt', 'data2.txt', 'data3.txt', 'data4.txt']

вход в loopFiles такой же.

В этот момент с forEach каждый обратный вызов получает индивидуальное имя файла.

Если бы я когда-нибудь столкнулся с кирпичной стеной с массивом, я бы не использовал этот подход. Но это всегда срабатывало.

Нет ничего страшного, я всегда могу обновить код, чтобы убрать обработку массива. Реальная проблема в том, что он работает в одной среде, но не работает в другой. Тем не менее, Node, V8 и Async - это одни и те же версии.

Я только что запустил слегка измененный код в Ubuntu 16.04 в узлах 6.0.0 и 6.2.2. В обоих случаях я получил одинаковый результат:

  • data1.txt, обратный вызов для первого элемента (data1.txt)
  • Ошибка: обратный вызов уже был вызван

Измененный скрипт:

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

Но в винде вы не пробовали.

Конечно, я закрываю это как не асинхронную проблему.

В понедельник, 27 июня 2016 г., в 20:20, Шелли Пауэрс [email protected]
написал:

Но в винде вы не пробовали.

-
Вы получаете это, потому что изменили состояние открытия / закрытия.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/caolan/async/issues/1199#issuecomment -228914233 или отключить звук
нить
https://github.com/notifications/unsubscribe/ADUIEDNwRmcEjcAnVmSCHBBIHvdM6DL3ks5qQGiwgaJpZM4I_Nsg
.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги