Async: 非同期は、関数の実行時に配列の変更から保護しません

作成日 2014年07月04日  ·  6コメント  ·  ソース: caolan/async

非同期呼び出しがある場合。 async.eachであり、その実行時に、渡された配列に変更が加えられると、配列が終了しないか、コールバックが2回呼び出されます。

例:

async = require "async" 
arr = [1, 2, 3]  
async.each arr, ((i, cb) -> console.log "i"; setImmediate(cb)), (err) -> console.log "done" 
arr.push(4)

この例では、3つの元の配列要素をループし、 iを出力しますが、 async.eachでは次のことを行っているため、コールバックを呼び出すことはありません。

if (completed >= arr.length) {
  callback(null);
}

非同期コードを見ると、変更される可能性のあるarr.lengthとの比較が行われています...元の配列の長さを保存してそれと比較し、完了したコールバックが呼び出されるようにすることをお勧めします。 ?

フィドル:
http://jsfiddle.net/4ysKX/1/

bug

最も参考になるコメント

非同期は、事後に配列の変更を許可しないことになりましたか? 事後に元の配列を変更して、最初よりも多くの要素を反復するのがよいというユースケースがあります。

全てのコメント6件

その通りです。変更しないでください。 後で変更する必要がある場合は、配列を非同期関数に渡す前に配列のクローンを作成します。

@aearlyはい、それは

入力を複製せずに_any_配列の変更から保護することは困難です。たとえば、イテレータ関数の同期変更ですが、反復に関係のない_asynchronous_変更から保護することは、クローンがなくても簡単です。実際には、 arr.length想定していません

(私は@bradensと協力してい

テスト付きのPRは歓迎されますが、それをマージするのは最終的には

これを行うことの欠点は、配列コピーの余分なオーバーヘッドです。 大きな配列がある場合、またはasync.each何度も呼び出している場合は、速度が遅くなり、より多くのメモリを使用します。

配列のコピーはオーバーヘッドが大きすぎることに同意します。 配列の最初の反復は同期的であるため、後で確認するために元の配列の長さを保存できることをお勧めします。 そうすれば、その間に配列が変更された場合でも、コールバック呼び出しの数はイテレーター呼び出しの数と一致します。 これは簡単で、 async.eachオーバーヘッドはゼロであるはずですが、他の関数についてはまだ調べていません。 これらの場合、すべての並列関数が一貫した動作をするのは素晴らしいことです。

これは#557の複製です。

非同期は、事後に配列の変更を許可しないことになりましたか? 事後に元の配列を変更して、最初よりも多くの要素を反復するのがよいというユースケースがあります。

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