使用键异步循环遍历数组

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 数组本身的函数扩展修改的,您可以像习惯的那样将数组方法链接在一起。