массивы JavaScript.уменьшить с помощью async/await

похоже, возникли некоторые проблемы с включением async /await С.reduce (), например:

const data = await bodies.reduce(async(accum, current, index) => {
  const methodName = methods[index]
  const method = this[methodName]
  if (methodName == 'foo') {
    current.cover = await this.store(current.cover, id)
    console.log(current)
    return {
      ...accum,
      ...current
    }
  }
  return {
    ...accum,
    ...method(current.data)
  }
}, {})
console.log(data)

на

3 ответов


проблема в том, что ваши значения аккумулятора являются обещаниями - они возвращают значения async functions. Чтобы получить последовательную оценку (и вообще все, кроме последней итерации), вам нужно использовать

const data = await array.reduce(async (accumP, current, index) => {
  const accum = await accumP;
  …
}, Promise.resolve(…));

что сказано, ибо async/await Я бы вообще рекомендовал используйте простые циклы вместо методов итерации массива, они более эффективны и часто проще.


вы можете обернуть всю карту/уменьшить блоки итератора в свое собственное обещание.примите решение и дождитесь завершения. Проблема, однако, в том, что аккумулятор не содержит результирующих данных/объекта, которые вы ожидаете на каждой итерации. Из-за внутренней цепи async/await/Promise аккумулятор будет фактическими обещаниями, которые, вероятно, еще предстоит решить, несмотря на использование ключевого слова await перед вашим вызовом в магазин (что может заставить вас поверить, что итерация фактически не вернется, пока этот вызов не завершится и аккумулятор не будет обновлен.

хотя это не самое элегантное решение, один вариант у вас есть, чтобы переместить сведения переменная объекта вне области видимости и назначьте ее как пусть так, что правильные вязка и мутация смогут произойти. Затем обновите этот объект данных внутри итератора, как разрешаются вызовы async/await/Promise.

/* allow the result object to be initialized outside of scope 
   rather than trying to spread results into your accumulator on iterations, 
   else your results will not be maintained as expected within the 
   internal async/await/Promise chain.
*/    
let data = {}; 

await Promise.resolve(bodies.reduce(async(accum, current, index) => {
  const methodName = methods[index]
  const method = this[methodName];
  if (methodName == 'foo') {
    // note: this extra Promise.resolve may not be entirely necessary
    const cover = await Promise.resolve(this.store(current.cover, id));
    current.cover = cover;
    console.log(current);
    data = {
      ...data,
      ...current,
    };
    return data;
  }
  data = {
    ...data,
    ...method(current.data)
  };
  return data;
}, {});
console.log(data);

мне нравится ответ Берги, я думаю, что это правильный путь.

Я также хотел бы упомянуть о моей библиотеке под названием Awaity.js

что позволяет легко использовать функции, такие как reduce, map & filter С async / await:

import reduce from 'awaity/reduce';

const posts = await reduce([1,2,3], async (posts, id) => {
  const res = await fetch('/api/posts/' + id);
  const post = res.json();

  return {
    ...posts,
    [id]: post
  }
}, {})

posts // { 1: { ... }, 2: { ... }, 3: { ... } }