web-dev-qa-db-ja.com

async.jsはそれぞれイテレータでインデックスを取得します

caolanのasync.js ライブラリ、具体的には.eachメソッドを使用しています。

イテレータのインデックスにどのようにアクセスしますか?

async.each(ary, function(element, callback){
  //do stuff here for each element in ary
  //how do I get access to the index?
}, function(err) {
  //final callback here
})
32
Kevin

async.forEachOfを使用できます。2番目の引数としてインデックスを使用してイテレータコールバックを呼び出します。

> async.forEachOf(['a', 'b', 'c'], function () {console.log(arguments)});
{ '0': 'a', '1': 0, '2': [Function] }
{ '0': 'b', '1': 1, '2': [Function] }
{ '0': 'c', '1': 2, '2': [Function] }

詳細については docs を参照してください

37
xuanji

更新

この答えを書いて以来、より良い解決策があります。詳細は xuanjiの答え をご覧ください

元の

以下のコメントの簡単で簡潔な例については、@ genexpに感謝します...

async.each(someArray, function(item, done){
    console.log(someArray.indexOf(item));
});

ドキュメントを読んで、リスト内の位置を表す整数にアクセスする方法がないと思いました...

配列内の各項目に反復関数を適用しますin parallel。反復子は、リストからの項目と終了時のコールバックを使用して呼び出されます。イテレータがこのコールバックにエラーを渡すと、各関数のメインコールバックがすぐにエラーとともに呼び出されます。

この関数はイテレータを各アイテムに並列に適用するため、イテレータ関数が順番に完了する保証はないことに注意してください。

そこで、もう少し掘り下げました( ソースコードリンク

async.each = function (arr, iterator, callback) {
        callback = callback || function () {};
        if (!arr.length) {
            return callback();
        }
        var completed = 0;
        _each(arr, function (x) {
            iterator(x, only_once(function (err) {
                if (err) {
                    callback(err);
                    callback = function () {};
                }
                else {
                    completed += 1;
                    if (completed >= arr.length) {
                        callback(null);
                    }
                }
            }));
        });
    };

ご覧のとおり、completedカウントがあり、各コールバックが完了すると更新されますが、実際のインデックス位置は更新されません。

ちなみに、JavaScriptは 純粋にシングルスレッド であるため、completedカウンターを更新する際の競合状態に問題はありません。

編集:イテレータをさらに掘り下げると、mightindexを参照できるようになりますクロージャーのおかげで変数...

async.iterator = function (tasks) {
    var makeCallback = function (index) {
        var fn = function () {
            if (tasks.length) {
                tasks[index].apply(null, arguments);
            }
            return fn.next();
        };
        fn.next = function () {
            return (index < tasks.length - 1) ? makeCallback(index + 1): null;
        };
        return fn;
    };
    return makeCallback(0);
};
36
Basic

async.forEachOf()を使用してください。

async.forEachOf(arr, function(value, index, callback) { ... }, ...

詳細については、ドキュメント here を参照してください。

9
Alain Beauvois

メソッドasync.each()は、配列をparallelで繰り返しますが、要素のインデックスを繰り返しコールバックに提供しません。

あなたが持っているとき:

_function( done ){

  async.each(

    someArray,

    function( item, cb ){
      // ... processing

      cb( null );
    },

    function( err ){
      if( err ) return done( err );

      // ...
      done( null );
    }
  );
}
_

それを見つけるにはArray.indexOf()を使用する必要があります:

_function( done ){

  async.each(

    someArray,

    function( item, cb ){
      // ... processing

      var index = someArray.indexOf( item );

      cb( null );
    },

    function( err ){
      if( err ) return done( err );

      // ...
      done( null );
    }
  );
}
_

これには、配列のすべての反復のために、配列内のメモリ内検索が必要です。大規模な配列の場合、これによりすべてが非常に遅くなります。

より良い回避策は、代わりにasync.eachSeries()を使用して、インデックスを自分で追跡することです。

_function( done ){

  var index = -1;
  async.eachSeries(

    someArray,

    function( item, cb ){

      // index is updated. Its first value will be `0` as expected
      index++;

      // ... processing

      cb( null );
    },

    function( err ){
      if( err ) return done( err );

      // ...
      done( null );
    }
  );
}
_

eachSeries()を使用すると、正しい順序で処理されることが保証されます。

asyncのメンテナーの最初の選択 である別の回避策は、Object.keysで繰り返すことです:

_function( done ){

  async.each(

    Object.keys( someArray ),

    function( key, cb ){

      // Get the value from the key          
      var item = someArray[ key ];

      // ... processing

      cb( null );
    },

    function( err ){
      if( err ) return done( err );

      // ...
      done( null );
    }
  );
}
_

これがお役に立てば幸いです。

3
Merc
  1. indexOfソリューションは遅いため、大きな配列には使用しないでください。
  2. mercのeachSeriesソリューションは、あなたが望むものを作りません。
  3. 効果的な回避策は、インデックスを持つ別の配列を作成することです。
someArrayWithIndexes = someArray.map(function(e, i) {return {obj: e, index: i}});
async.each(someArrayWithIndexes , function(item, done){
    console.log("Index:", item.index);
    console.log("Object:", item.obj);
});
0
x3mka