使用键异步循环遍历数组
Asynchronously loop through array with key
我有一组客户,我想遍历他们并为每个客户分配一个 属性。添加了 属性 的客户对象通过 details 函数返回
for (let i = 0; i < customers.length; i++)
{
customers[i] = await details(customers[i]);
}
我目前就是这样做的,但它是同步的。我希望列表中的所有对象一次异步完成。我正在尝试使用异步库,但它只给我循环内可用的客户对象,因此客户数组永远不会改变。
async.forEachOf(customers, (customer, finished) async =>
{
customer = await details(customer);
finished();
});
我还能怎么做?谢谢
您不需要第三方库即可完成此操作。只需使用 Promise.all()
and Array.prototype.map()
.
const customerDetails = await Promise.all(
customers.map(customer => details(customer))
);
此代码将运行 details()
一个接一个地为每个客户提供服务,而无需等待前一个客户。您创建了一系列承诺并在最后等待它们
const promises = [];
for (let i = 0; i < customers.length; i++) {
let p = new Promise(async (resolve, reject) => {
customers[i] = await details(customers[i]);
resolve();
});
promises.push(p);
}
await Promise.all(promises);
A library is not required 异步迭代项目数组。
例如异步处理这个数组:
const arr = [1, 2, 3];
首先,从一个数组创建一个生成器,这样你就可以为数组中的每一项生成执行:
/**
* A convenience function for creating a ES2015 Generator to iterate over
* items in an array.
*
* @template T
* @param {T[]} value
*/
function* toIterator<T>(value: T[]) {
const generator = value[Symbol.iterator]();
for (let generated of generator) {
yield generated;
}
}
然后,异步遍历数组的关键是让函数在提供的 handler
.
的 resolve
上调用自身
/**
* Provides the ability to process an iterator's values asynchronously
* with a predicate, `hander`.
*
* @template T
* @template TReturn
* @template TNext
* @param {Generator<T, TReturn, TNext>} generator
* @param {(arg: T) => Promise<TReturn>} handler
* @returns
*/
async function iterateAsynchronously<T, TReturn, TNext>(
generator: Generator<T, TReturn, TNext>,
handler: (arg: T) => Promise<TReturn>
) {
const iterate: () => Promise<TReturn> = async () => {
const generated = generator.next();
if (generated.done) {
return generated.value;
}
return handler(generated.value).then(iterate);
};
return iterate();
}
如果您愿意,可以使用其中一种或两种方法扩展全局数组。 Another example.
这将允许您在异步处理项目后将更多数组方法链接在一起:
const run = async () => {
const arr = [1, 2, 3, 4];
console.log((await arr.iterateAsynchronously((val) => new Promise(r => {
setTimeout(r, 2000);
console.log('Processing', val);
}))).reverse());
}
run();
在这种情况下,由于数组原型是用 returns 数组本身的函数扩展修改的,您可以像习惯的那样将数组方法链接在一起。
我有一组客户,我想遍历他们并为每个客户分配一个 属性。添加了 属性 的客户对象通过 details 函数返回
for (let i = 0; i < customers.length; i++)
{
customers[i] = await details(customers[i]);
}
我目前就是这样做的,但它是同步的。我希望列表中的所有对象一次异步完成。我正在尝试使用异步库,但它只给我循环内可用的客户对象,因此客户数组永远不会改变。
async.forEachOf(customers, (customer, finished) async =>
{
customer = await details(customer);
finished();
});
我还能怎么做?谢谢
您不需要第三方库即可完成此操作。只需使用 Promise.all()
and Array.prototype.map()
.
const customerDetails = await Promise.all(
customers.map(customer => details(customer))
);
此代码将运行 details()
一个接一个地为每个客户提供服务,而无需等待前一个客户。您创建了一系列承诺并在最后等待它们
const promises = [];
for (let i = 0; i < customers.length; i++) {
let p = new Promise(async (resolve, reject) => {
customers[i] = await details(customers[i]);
resolve();
});
promises.push(p);
}
await Promise.all(promises);
A library is not required 异步迭代项目数组。
例如异步处理这个数组:
const arr = [1, 2, 3];
首先,从一个数组创建一个生成器,这样你就可以为数组中的每一项生成执行:
/**
* A convenience function for creating a ES2015 Generator to iterate over
* items in an array.
*
* @template T
* @param {T[]} value
*/
function* toIterator<T>(value: T[]) {
const generator = value[Symbol.iterator]();
for (let generated of generator) {
yield generated;
}
}
然后,异步遍历数组的关键是让函数在提供的 handler
.
resolve
上调用自身
/**
* Provides the ability to process an iterator's values asynchronously
* with a predicate, `hander`.
*
* @template T
* @template TReturn
* @template TNext
* @param {Generator<T, TReturn, TNext>} generator
* @param {(arg: T) => Promise<TReturn>} handler
* @returns
*/
async function iterateAsynchronously<T, TReturn, TNext>(
generator: Generator<T, TReturn, TNext>,
handler: (arg: T) => Promise<TReturn>
) {
const iterate: () => Promise<TReturn> = async () => {
const generated = generator.next();
if (generated.done) {
return generated.value;
}
return handler(generated.value).then(iterate);
};
return iterate();
}
如果您愿意,可以使用其中一种或两种方法扩展全局数组。 Another example.
这将允许您在异步处理项目后将更多数组方法链接在一起:
const run = async () => {
const arr = [1, 2, 3, 4];
console.log((await arr.iterateAsynchronously((val) => new Promise(r => {
setTimeout(r, 2000);
console.log('Processing', val);
}))).reverse());
}
run();
在这种情况下,由于数组原型是用 returns 数组本身的函数扩展修改的,您可以像习惯的那样将数组方法链接在一起。