Search code examples
javascriptes6-promise

How to use reduce in a Promise.all instead of map


How can I use reduce in the place of map when using Promise.all? My attempt results in an error UnhandledPromiseRejectionWarning: TypeError: #<Promise> is not iterable at Function.all (<anonymous>)

Eventually I would like to conditionally add innerResult to memo but I need to use reduce first.

const _ = require('lodash');

const eq = [{id:1}, {id:2}, {id:3}];

// block to replace
var biggerEq = _.map(eq, async (e) => {
  const innerResult = await wait(e.id);
  return innerResult;
})

// attempt at replacing above block
// var biggerEq = _.reduce(eq, async (memo, e) => {
//   const innerResult = await wait(e.id);
//   memo.push(innerResult)
//   return memo;
// }, []);

Promise.all(biggerEq).then((result) => {
  console.log(result) // outputs [ 2, 4, 6 ]
})


function wait (id) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(id  * 2);
    }, 1000);
  })
}

Solution

  • If you want to replace it with reduce, it's possible, but the logic will be a bit convoluted. Make the accumulator a Promise that resolves to an array that you can push to, then return it so the next iteration can use it (as a Promise):

    const eq = [{id:1}, {id:2}, {id:3}];
    
    function wait (id) {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(id  * 2);
        }, 1000);
      })
    }
    
    const biggerEq = _.reduce(eq, async (arrProm, obj) => {
      const [arr, innerResult] = await Promise.all([arrProm, wait(obj.id)]);
      arr.push(innerResult);
      return arr;
    }, Promise.resolve([]));
    
    biggerEq.then((arr) => {
      console.log(arr);
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

    (but .map is really more appropriate when you want to transform one array into another)