buydadip
buydadip

Reputation: 9437

Koa - Async function within Async function error handling

In my app.js I have the following...

app.use(async (ctx, next) => {
  try {
    await next()
  } catch (err) {
    ctx.status = 400
    ctx.body = `Uh-oh: ${err.message}`
    console.log('Error handler:', err.message)
  }
});

app.use(router());

Then in routes I have defined...

router.post('/', retrieve);

The logic for retrieve is structured as so...

const retrieve = async ctx => {
  Object.keys(ctx.request.files).forEach((key) => {
    process(files[key]);
  });
};

Now let's say I throw an error in retrieve...

const retrieve = async ctx => {
  throw new Error(`Error!`);
  Object.keys(ctx.request.files).forEach((key) => {
    process(files[key]);
  });
};

This will work correctly and bubble up all the way to app.js. However, the process function is also using async, if I throw the error there instead...

const retrieve = async ctx => {
  Object.keys(ctx.request.files).forEach((key) => {
    process(files[key]);
  });
};

const process = async (file) => {
  throw new Error(`Error!`);
  ...

I get the following error...

UnhandledPromiseRejectionWarning: Error: Error!

Why am I getting UnhandledPromiseRejectionWarning? How can I fix it and make it so that any error thrown inside of process gets bubbled up to app.js?

Upvotes: 0

Views: 309

Answers (1)

Priyadarshan Vijay
Priyadarshan Vijay

Reputation: 85

As the forEach loop is not async, the errors get thrown after it's execution and are therefore not able to bubble up to app.js. Now there are two solutions to it, either you can use a for loop, or map the promises and wait for all of them to resolve. Sample code according to your problem :

  1. For calling process sequentially
const retrieve = async ctx => {
    const ctxKeys = Object.keys(ctx.request.files);
    for(let i = 0 ; i < ctxKeys.length ;++i){
        await process(files[ctxKeys[i]]);
    }
};

  1. For calling process asynchronously
const retrieve = async ctx => {
   await Promise.all(Object.keys(ctx.request.files).map(async (key) => {
     await process(files[key]);
   }));
};

Upvotes: 1

Related Questions