37

我正在使用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
})
4

6 回答 6

39

您可以使用async.forEachOf- 它以索引作为第二个参数调用其迭代器回调。

> 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] }

有关更多信息,请参阅文档。

于 2015-08-05T01:17:02.403 回答
38

更新

自从写了这个答案,现在有了更好的解决方案。详情请看玄机的回答

原来的

感谢@genexp在下面的评论中提供了一个简单而简洁的示例...

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

阅读文档后,我怀疑没有任何方法可以访问表示列表中位置的整数......

并行地将迭代器函数应用于数组中的每个项目。使用列表中的项目和完成时的回调调用迭代器。如果迭代器将错误传递给此回调,则每个函数的主回调都会立即调用错误。

请注意,由于此函数将迭代器并行应用于每个项目,因此无法保证迭代器函数将按顺序完成。

所以我挖得更深一些(源代码链接

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,每次回调完成时都会更新一个计数,但没有实际的索引位置。

顺便说一句,更新计数器的竞争条件没有问题,completed因为 JavaScript 在后台是纯粹的单线程

编辑:在深入挖掘迭代器之后,看起来你可以index通过闭包来引用一个变量......

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);
};
于 2013-07-07T22:40:32.083 回答
9

只需使用async.forEachOf().

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

有关详细信息,请参阅此处的文档。

于 2016-03-18T06:30:17.133 回答
3

该方法将并行async.each()迭代数组,并且它不向迭代回调提供元素的索引。

所以当你有:

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(),您可以保证事情将以正确的顺序完成。

另一种解决方法是使用 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 );
    }
  );
}

我希望这有帮助。

于 2015-03-08T23:23:53.017 回答
1

Modern-async 的forEach()实现类似,但允许您访问索引。

于 2020-12-20T19:35:21.353 回答
0
  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);
});
于 2015-05-20T20:43:15.493 回答