2

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: 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.

8
  • What do you expect the result to be? Why are you using reduce? Do you want the doSomething tasks to happen concurrently? Commented Aug 18, 2017 at 2:49
  • anArray is a set of Postgres queries that need to happen in sequence. result is the result of the final pg query operation, and is returned to the calling function. The code works as written, but simulating a database error causes node to throw UnhandledPromiseRejectionWarning. Commented Aug 18, 2017 at 2:57
  • Actually, the code in your question does not run the queries in sequence, and result is always undefined. Commented Aug 18, 2017 at 3:07
  • Shoot. Accidentally working code is the worst. The code definitely executes the items in anArray in sequence and result definitely holds the value I expect. What am I missing? Commented Aug 18, 2017 at 3:16
  • Have you shown us your actual code? What is doSomething - maybe it does some internal queuing? Commented Aug 18, 2017 at 3:21

2 Answers 2

3

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);
  }
}
Sign up to request clarification or add additional context in comments.

16 Comments

How does Answer address issue described at Question?
@guest271314 It shows how to avoid the unhandled rejection warning.
What is the difference between the code at Question and code at Answer?
@guest271314 What difference don't you see? It should be obvious that they're two different things.
@sheepgobeep Yes. (It could've been await doSomething(b) instead of the return, that doesn't make a difference). But by awaiting a, we don't leave the a promise - the result of the previous iteration - hanging around nowhere. Maybe it helps to write out what reduce does with its callback and accumulator for a small example (say, anArray of three elements) on a sheet of paper.
|
0

To avoid the UnhandledPromiseRejectionWarning you can chain .catch() to aFunction() call or utilizing second parameter of .then() to handle the rejected Promise or error.

Alternatively, chain .catch() to doSomethingTo(b) call to handle the error.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.