我就是这样做的:
function processArray(array, index, callback) {
processItem(array[index], function(){
if(++index === array.length) {
callback();
return;
}
processArray(array, index, callback);
});
};
function processItem(item, callback) {
// do some ajax (browser) or request (node) stuff here
// when done
callback();
}
var arr = ["url1", "url2", "url3"];
processArray(arr, 0, function(){
console.log("done");
});
有什么好处吗?如何避免那些意大利面条的代码?
答案 0 :(得分:30)
签出async库,它是为了控制流(异步东西),它有很多方法用于数组:每个,过滤器,映射。查看github上的文档。以下是您可能需要的内容:
每个(arr,迭代器,回调)
并行地对数组中的每个项应用迭代器函数。使用列表中的项目调用迭代器,并在完成时调用它。如果迭代器将错误传递给此回调,则会立即调用each
函数的主回调并显示错误。
eachSeries(arr,iterator,callback)
与each
相同,只有迭代器才会串行应用于数组中的每个项目。只有当前的迭代器完成处理后才会调用下一个迭代器。这意味着迭代器函数将按顺序完成。
答案 1 :(得分:17)
如某些答案所指出,可以使用" async"图书馆。但有时你不想在你的代码中引入新的依赖。下面是循环和等待完成某些异步函数的另一种方法。
var items = ["one", "two", "three"];
// This is your async function, which may perform call to your database or
// whatever...
function someAsyncFunc(arg, cb) {
setTimeout(function () {
cb(arg.toUpperCase());
}, 3000);
}
// cb will be called when each item from arr has been processed and all
// results are available.
function eachAsync(arr, func, cb) {
var doneCounter = 0,
results = [];
arr.forEach(function (item) {
func(item, function (res) {
doneCounter += 1;
results.push(res);
if (doneCounter === arr.length) {
cb(results);
}
});
});
}
eachAsync(items, someAsyncFunc, console.log);
现在,正在运行node iterasync.js
将等待大约三秒钟,然后打印[ 'ONE', 'TWO', 'THREE' ]
。这是一个简单的例子,但它可以扩展到处理许多情况。
答案 2 :(得分:9)
正如所指出的,你必须使用setTimeout,例如:
each_async = function(ary, fn) {
var i = 0;
-function() {
fn(ary[i]);
if (++i < ary.length)
setTimeout(arguments.callee, 0)
}()
}
each_async([1,2,3,4], function(p) { console.log(p) })
答案 3 :(得分:3)
处理数组(或任何其他可迭代的)异步迭代的最简单方法是使用await运算符(仅在异步函数中)和for循环。
(async function() {
for(let value of [ 0, 1 ]) {
value += await(Promise.resolve(1))
console.log(value)
}
})()
&#13;
您可以使用库来转换您可能需要的任何接受回调的函数来返回promises。
答案 4 :(得分:0)
在现代 JavaScript 中,有一些有趣的方法可以将 Array 扩展为异步 itarable 对象。
在这里,我想展示一个全新类型 > klout@0.1.0 dev
> next dev
Loaded env from [path]/.env.local
的骨架,它通过继承它的优点来扩展 AsyncArray
类型只是为了成为一个异步可迭代数组。
这仅在现代引擎中可用。下面的代码使用了最新的噱头,如 private instance fields 和 for await...of
。
如果您不熟悉它们,那么我建议您提前查看上面链接的主题。
Array
所以一个异步可迭代数组必须包含承诺。只有这样,它才能返回一个迭代器对象,该对象在每次 class AsyncArray extends Array {
#INDEX;
constructor(...ps){
super(...ps);
if (this.some(p => p.constructor !== Promise)) {
throw "All AsyncArray items must be a Promise";
}
}
[Symbol.asyncIterator]() {
this.#INDEX = 0;
return this;
};
next() {
return this.#INDEX < this.length ? this[this.#INDEX++].then(v => ({value: v, done: false}))
: Promise.resolve({done: true});
};
};
调用时都会返回一个承诺,最终将 next()
转化为 resolve
或 {value : "whatever", done: false}
之类的对象。所以基本上所有返回的东西都是一个承诺。 {done: true}
抽象解压缩其中的值并将其提供给我们。
现在正如我之前提到的,这个 await
类型,因为从 AsyncArray
扩展,允许我们使用我们熟悉的那些 Array 方法。这应该会简化我们的工作。
让我们看看会发生什么;
Array