Async: async.forEachLimitを使用して「最大呼び出しスタックサイズを超えました」

作成日 2011年12月26日  ·  15コメント  ·  ソース: caolan/async

async = require('async');

var documents = ['a', 'b', 'c', 'd', 'e', 'f'];

async.forEachLimit(documents, 2, function(item, callback) {
  console.log(".", item);
  callback(null);
}, function(err){
  console.log("end", err);
});

ログ

$ node test.js
. a
. a
. a
. a
. a
. a
end undefined
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
[...]

node.js:134
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
RangeError: Maximum call stack size exceeded

最も参考になるコメント

同期操作をしていました。 次のように変更して修正しました。

callback();

setTimeout(callback, 0);

全てのコメント15件

forEachLimitは間違っているようです。

started += 1 running += 1

イテレータ呼び出しの前に移動する必要があります。 arr[started]arr[started - 1]に変更する必要があります

注:このバグが発生するのは、イテレーターイテレーター内のコードが同じティックでコールバックを呼び出す場合のみです。

async.jsでSYNC関数の呼び出しを停止します

イテレータに条件付きreturn callback(null);があるときに、この問題が発生しました。 つまり、 async.forEachを適用する前にArray.filterを使用して配列をフィルタリングするという、よりスマートなことをしなければならなかったので、実際にはちょっと役に立ちました...

_本当に_すべきだと思う場合は、 process.nextTick(function() { callback(); })を使用してこれを回避できます。

@jacobraskそれはうまくいきました。 ありがとう

callback(null);の実行は同期的です。 非同期で呼び出す必要があります。つまり、 process.nextTick(callback) 、またはprocess.nextTick(function() { callback(null); });です。 @bobrikが言ったように、非同期で同期関数の呼び出しを停止します:)

「非同期で同期関数の呼び出しを停止する」と言っても、要点が欠けています。これは壊れており、これが問題であると思われるのはforEachLimitだけです。

async.forEachLimit(['a','b'], 1, function(item, callback){
  if(something) {
    doStuff(function(){ callback(); });
  } else {
    callback();
  }
});

その非常に具体的な例( @jacobraskがフィルタリングで言及しているように)からかなり簡単に保護できますが、doStuff()(私の制御外のライブラリにある可能性があります)がprocess.nextTick()なしでコールバックを呼び出すことを決定した場合はどうなりますか?

これらの場合にスタックオーバーフローを回避する必要がある同期イテレータを検出した場合にasync.nextTickを呼び出すコードを追加しました。 しかし、真剣に、非同期で同期機能を呼び出すのをやめてください! ...代わりに、関数を一貫して同期または一貫して非同期にします;)

これはasync.eachSeriesでも起こりました。

mapLimitでも発生します。これは模擬関数であるため、私の関数は同期です。 次に、それをsetImmediateでラップすると、問題は解決しました。

async.forEachOfLimitで私と一緒に起こります

async.waterfallで同じ問題に直面しています。

もちろん、async.queueも。

同期操作をしていました。 次のように変更して修正しました。

callback();

setTimeout(callback, 0);

これは、約束にキャッチが付いていたときに起こりました。 何かのようなもの:
async.forEach(items, (item:any, callback:Function) => { someAsyncPromise(item).then(() => { callback(); }).catch((err) => { //console error or something here callback(); }) });

このエラーはpromiseで例外が発生した場合にのみスローされるため、catchはpromiseの非同期ビットの前にスローする必要があります。

`

非同期で同期関数を呼び出すのをやめるべきだと理解しています。

しかし、非同期本体内でsync関数callback()を呼び出すことが間違っている場合、なぜ非同期ドキュメントは例でそれを示しているのですか?

誰かが代わりに非同期モジュールを操作するための「適切な」方法を理解するのを手伝ってもらえますか?

非同期ドキュメントから直接の例を次に示します。

// assuming openFiles is an array of file names
async.each(openFiles, function(file, callback) {

    // Perform operation on file here.
    console.log('Processing file ' + file);

    if( file.length > 32 ) {
      console.log('This file name is too long');
      callback('File name too long');
    } else {
      // Do work to process file here
      console.log('File processed');
      callback();
    }
}, function(err) {
    // if any of the file processing produced an error, err would equal that error
    if( err ) {
      // One of the iterations produced an error.
      // All processing will now stop.
      console.log('A file failed to process');
    } else {
      console.log('All files have been processed successfully');
    }
});

https://caolan.github.io/async/docs.html#each

ありがとう!

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