Search code examples
javascriptreactjsasynchronousasync-awaites6-promise

Throwing errors in async await functions and catching from where it's called


How can we catch error from an async await function from where it's called?

For example, I have a React component which calls a async-await function imported from another module. When I use Promise.reject("An unknown has occurred"); in that function, so in my React component why can't I get the error in asyncAwaitFunction.catch((e)=>console.log(e))?

I even tried throw "An unknown occured", but it doesn't seem to work.

react component

const handleSubmit = async (e) => {
    e.preventDefault();
    add(formData, code)
      .then(() => router.push("/dashboard/manage"))
      .catch((e) => setError(e)); //I want error to be catched here
  };

functions.js

export const addUser = async (details, code) => {

 const isExist = await isUser(code);

 if (!isExist) {

  const add = db.batch();    //firebase batch write

  add.set(userID(code), details);    //Add details to databse

  add.commit()
   .catch((e)=> {
   console.log(e);    // error occurs confirmed
   Promise.reject("Unknown error occurred"); //this does't get catched in component.
  });
    
 } else {
   Promise.reject("Already Exists!"); 
 }
};

Solution

  • A rejected Promise (either from a Promise that you constructed that rejected, or from a Promise.reject) will only be caught if:

    • a .catch is added onto the end of that Promise expression, or
    • that Promise expression is returned inside an async function or a .then, and the caller of the async function or after the .then callback, there's a .catch

    So, you should change to something like:

    export const addUser = async (details, code) => {
       const isExist = await isUser(code);
       if (isExist) {
          return Promise.reject('Already Exists!');
       }
    
       const add = db.batch();    //firebase batch write
       add.set(userID(code), details);    //Add details to databse
       return add.commit().catch((e) => {
          console.log(e);    // error occurs confirmed
          return Promise.reject("Unknown error occurred");
       });
    };
    

    But do you really need to log in the .commit().catch? If not, it'd be cleaner to just return the commit Promise and catch in the caller:

    export const addUser = async (details, code) => {
       const isExist = await isUser(code);
       if (isExist) {
          return Promise.reject('Already Exists!');
       }
    
       const add = db.batch();    //firebase batch write
       add.set(userID(code), details);    //Add details to databse
       return add.commit();
    };
    

    A Promise that is awaited or returned from an async function will have its errors (or its resolve value) percolate up to the caller of the async function.