Swix
Swix

Reputation: 2123

Try...catch vs .catch

So I have this user service functions in service.ts which includes database stuffs.

export const service = {
  async getAll(): Promise<User[]> {
    try {
      const result = await query
      return result
    } catch (e) {
      report.error(e)
      throw new Error(e)
    }
  },

  ...
}

And query.ts file for some reasons, eg: caching, business logic, etc.

export const query = {
  async index(): Promise<User[]> {
    try {
      const result = await service.getAll()
      return result
    } catch (e) {
      report.error(e)
      throw new Error(e)
    }
  },

  ...
}

And another upper layer for routers and resolvers, because I want to see all routes in one file.

export const resolver = {
  Query: {
    users: (): Promise<User[]> => query.index(),
  },

  ...
}

Do I need to wrap try...catch in all functions? Or can't I just add .catch at the very top layer like this:

export const resolver = {
  Query: {
    users: (): Promise<User[]> => query.index().catch(e => e),
  },

  ...
}

Upvotes: 4

Views: 5134

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1075815

Do I need to wrap try...catch in all functions?

No, you don't, not unless you want to log it at every level for some reason. Just handle it at the top level.

In an async function, promise rejections are exceptions (as you know, since you're using try/catch with them), and exceptions propagate through the async call tree until/unless they're caught. Under the covers, async functions return promises and reject those promises when a synchronous exception occurs or when a promise the async function is awaiting rejects.

Here's a simple example:

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function outer() {
    // ...
    await delay(10);
    
    console.log("before calling inner");
    await inner();
    console.log("after calling inner (we never get here)");
}

async function inner() {
    // ...
    await delay(10);
    
    console.log("inside inner");
    
    // Something goes wrong
    null.foo();
}

outer()
.catch(e => {
    console.log("Caught error: " + e.message, e.stack);
});


Just as a side note: If you do catch an error because you want to do X before the error propagates and you're going to re-throw the error after you do X, best practice is to re-throw the error you caught, rather than creating a new one. So:

} catch (e) {
    // ...do X...
    throw e; // <== Not `throw new Error(e);`
}

But only do that if you really need to do X when an error occurs. Most of the time, just leave the try/catch off entirely.

Upvotes: 6

Related Questions