Steve Robinson
Steve Robinson

Reputation: 3939

Throw custom errors async/await try-catch

Let's say I have a function like this -

doSomeOperation = async () => {
  try {
    let result = await DoSomething.mightCauseException();
    if (result.invalidState) {
      throw new Error("Invalid State error");
    }

    return result;
  } catch (error) {
    ExceptionLogger.log(error);
    throw new Error("Error performing operation");
  }
};

Here the DoSomething.mightCauseException is an asynchronous call that might cause an exception and I'm using try..catch to handle it. But then using the result obtained, I might decide that I need to tell the caller of doSomeOperation that the operation has failed with a certain reason.

In the above function, the Error I'm throwing is caught by the catch block and only a generic Error gets thrown back to the caller of doSomeOperation.

Caller of doSomeOperation might be doing something like this -

doSomeOperation()
  .then((result) => console.log("Success"))
  .catch((error) => console.log("Failed", error.message))

My custom error never gets here.

This pattern can be used when building Express apps. The route handler would call some function which might want to fail in different ways and let the client know why it failed.

I'm wondering how this can be done? Is there any other pattern to follow here? Thanks!

Upvotes: 3

Views: 3119

Answers (2)

Chathura Widanage
Chathura Widanage

Reputation: 663

Just change the order of your lines.

doSomeOperation = async() => {
    let result = false;
    try {
        result = await DoSomething.mightCauseException();
    } catch (error) {
        ExceptionLogger.log(error);
        throw new Error("Error performing operation");
    }
    if (!result || result.invalidState) {
        throw new Error("Invalid State error");
    }
    return result;
};

Update 1

Or you could create custom errors as below.

class MyError extends Error {
  constructor(m) {
    super(m);
  }
}

function x() {
  try {
    throw new MyError("Wasted");
  } catch (err) {
    if (err instanceof MyError) {
      throw err;
    } else {
      throw new Error("Bummer");
    }
  }

}

x();

Update 2

Mapping this to your case,

class MyError extends Error {
  constructor(m) {
    super(m);
  }
}

doSomeOperation = async() => {
  try {
    let result = await mightCauseException();
    if (result.invalidState) {
      throw new MyError("Invalid State error");
    }

    return result;
  } catch (error) {
    if (error instanceof MyError) {
      throw error;
    }
    throw new Error("Error performing operation");
  }
};

async function mightCauseException() {
  let random = Math.floor(Math.random() * 1000);
  if (random % 3 === 0) {
    return {
      invalidState: true
    }
  } else if (random % 3 === 1) {
    return {
      invalidState: false
    }
  } else {
    throw Error("Error from function");
  }
}


doSomeOperation()
  .then((result) => console.log("Success"))
  .catch((error) => console.log("Failed", error.message))

Upvotes: 2

Revansiddh
Revansiddh

Reputation: 3062

You can simply use throw instead of using Error constructor

const doSomeOperation = async () => {
  try {
      throw {customError:"just throw only "}
  } catch (error) {
    console.log(error)
  }
};

doSomeOperation()

Upvotes: 0

Related Questions