Async: ノード6.2.2で非同期を使用して新しいエラーを取得する「コールバックはすでに呼び出されています」

作成日 2016年06月27日  ·  12コメント  ·  ソース: caolan/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( "コールバックはすでに呼び出されました。");
^

エラー:コールバックはすでに呼び出されています。

コードの次のセクションのコールバック関数

関数loopFiles(ファイル、コールバック){
files.forEach(関数(名前){
コールバック(null、名前);
});
}、

2回目の実行で失われます。

このコードは、Nodeのいくつかのバージョンで正常に実行されました。 ノード6が最初にリリースされたときにこれをテストしたと思います。

2回目の反復では、関数はnullではありませんが、非同期コードで何かが発生しているため、このエラーが発生します。

question

全てのコメント12件

ここで何度もコールバックを呼び出したため:

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

この場合はasync.forEachを使用してください。

面白い。 以前のバージョンのNodeで問題は発生していません。実際、これはWindowsマシンのNode6.0.0で正常に実行されました。

そのため、6.0.0と6.2.2の間で何かが変更され、組み込みのforEachを使用するとAsyncが機能しなくなりました。

参考までに、async.forEachは機能しません。 クラッシュしませんが、機能しません。

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

率直に言って、問題の原因がforEachであるかどうかはわかりません。 間違って使用している場合は、お知らせください。

OK、あきらめます。

Windowsマシンを6.2.2に更新しましたが、このコードは機能します。 しかし、私のLinuxマシンでは動作しません。 どちらも同じV8エンジンで構築されています。 どちらも同じバージョンの非同期を使用しています。 どちらにも同じサンプルファイルディレクトリがあります。

Linuxでは、エラーがスローされます。 Windowsではそうではありません。

@shelleypウォーターフォールは、複数のファイルに対して不適切に構造化されています。 それを2つの滝に分けるか、各ステップに配列を期待させたいと思います。

async.forEach変更が機能しなかった理由は、 loopFilesコールバックを呼び出していないためです。 firstFileを処理するだけの場合、その関数はとにかく期待どおりに機能しません。loopFilesを(files, callback) => callback(null, files[0])変更します。それ以外の場合は、 checkFilesreadDataが必要になります。 modifyは配列を期待します(または2番目のウォーターフォールを作成します)

すべてのコードを修正するつもりはありませんが、これが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がリストされている場合だけです。
1つのファイル(0ファイルの場合も壊れます)。

両方のバージョンのnodでreaddirの出力を再確認してもかまいません
2016年6月27日午後5時55分、「ShelleyPowers」 [email protected]は次のように書いています。

それはいいです。

これは6.2.2まで機能したことを知っているので、私のコードが機能しなくなった原因は何でも
作業すると、他の人のコードが機能しなくなる可能性があります。


開/閉状態を変更したため、これを受け取っています。
このメールに直接返信し、GitHubで表示してください
https://github.com/caolan/async/issues/1199#issuecomment -228887866、またはミュート
スレッド
https://github.com/notifications/unsubscribe/ADUIEAfvkwCmdjmkIZIjipFGYgPQ6SzYks5qQEbpgaJpZM4I_Nsg

このコードは常に複数のファイルで機能します。 ええと、Linuxでは6.2.2まで。

しかし、Windowsでチェックしただけです。 うん、4つのファイルで動作しました。

readdirの出力は['data1.txt'、 'data2.txt'、 'data3.txt'、 'data4.txt']です。

loopFilesへの入力は同じです。

その時点で、forEachを使用すると、各コールバックは個別のファイル名を取得します。

アレイでレンガの壁にぶつかったことがあれば、このアプローチは使用しなかったでしょう。 しかし、それは常に機能しました。

大したことではありません。いつでもコードを更新して配列処理を削除できます。 本当の問題は、ある環境では機能しますが、別の環境では機能しないことです。 ただし、Node、V8、およびAsyncは同じバージョンです。

Ubuntu16.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

しかし、あなたはそれをWindowsで試していませんでした。

確かに、非同期の問題ではないため、クローズします。

20:20時月、2016年6月27日には、シェリーパワーズ[email protected]
書きました:

しかし、あなたはそれをWindowsで試していませんでした。


開/閉状態を変更したため、これを受け取っています。
このメールに直接返信し、GitHubで表示してください
https://github.com/caolan/async/issues/1199#issuecomment -228914233、またはミュート
スレッド
https://github.com/notifications/unsubscribe/ADUIEDNwRmcEjcAnVmSCHBBIHvdM6DL3ks5qQGiwgaJpZM4I_Nsg

このページは役に立ちましたか?
0 / 5 - 0 評価