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
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
ありがとう!
最も参考になるコメント
同期操作をしていました。 次のように変更して修正しました。
に