sheepgobeep sheepgobeep - 1 month ago 10
Javascript Question

JavaScript error handling async function passed to reduce

I'm passing an

async
function to an array
reduce
function. What's the syntax for catching errors thrown by the passed in function? The reducing is happening inside a
try
catch
block, which is catching other errors just fine, but node gives me an
UnhandledPromiseRejectionWarning
if the passed in function itself throws an error.

Code:

aFunction = async (anArray) => {
try {
const result = await anArray.reduce(async (a, b) => {
await doSomethingTo(b);
}, Promise.resolve());

return result;
}

catch (error) {
winston.error(error);
}
}


(Edit) Actual code:

exports.chainedQueryDB = async (queries, finalTask, download) => {
let client = await pool.connect();
try {
winston.info(`Begin chained table query.`);
// Loop through query array
const result = await queries.reduce(async (a, b) => {
await client.query(b);
}, Promise.resolve());

if (download) {
return streamOut(download, client);
}

return result.rows;
}

catch (error) {
throw error;
}

finally {
const final = await client.query(finalTask);
winston.info(`Temp table dropped.`);
client.release();
}
}


(Edit) Report:
I need to spend more time with this depressingly trivial module to fully understand what's going on, but here's a preliminary report: Replacing
await client.query(b)
with
await a; return client.query(b);
solved the problem. With just
await client.query(b)
,
reduce
seemed to 1) generate a bunch of floating
client.query
calls that all ran even if an earlier promise was rejected, and 2) caused an unhandled promise rejection warning. Using
await a; return client.query(b);
stops execution on first rejection and the catch block catches the error as originally intended.

Answer Source

You need to do something with the promise in the accumulator (the a parameter) as well - await it, handle its errors by installing a .catch() callback, wait for it concurrently with the doSomething(b). For a sequential execution, you could do

async function aFunction(anArray) {
  try {
    return await anArray.reduce(async (a, b) => {
      await a; // make sure the previous query is done
      return doSomethingTo(b);
    }, Promise.resolve());
  } catch (error) {
    winston.error(error);
  }
}

I would hover recommend to simply not use reduce here:

async function aFunction(anArray) {
  try {
    let result;
    for (const b of anArray) {
      result = await doSomethingTo(b);
    }
    return result;
  } catch (error) {
    winston.error(error);
  }
}