Search code examples
javascriptpromiseasync-awaitreduceecmascript-next

JavaScript array .reduce with async/await


Seem to be having some issues incorporating async/await with .reduce(), like so:

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)

The data object is logged before the this.store completes...

I know you can utilise Promise.all with async loops, but does that apply to .reduce()?


Solution

  • The problem is that your accumulator values are promises - they're return values of async functions. To get sequential evaluation (and all but the last iteration to be awaited at all), you need to use

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

    That said, for async/await I would in general recommend to use plain loops instead of array iteration methods, they're more performant and often simpler.