我正在使用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
})
我正在使用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
})
您可以使用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] }
有关更多信息,请参阅文档。
自从写了这个答案,现在有了更好的解决方案。详情请看玄机的回答
感谢@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);
};
只需使用async.forEachOf()
.
async.forEachOf(arr, function(value, index, callback) { ... }, ...
有关详细信息,请参阅此处的文档。
该方法将并行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 );
}
);
}
我希望这有帮助。
Modern-async 的forEach()
实现类似,但允许您访问索引。
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); });