Correct Try...Catch Syntax Using Async/Await

Correct Try...Catch Syntax Using Async/Await

It seems to be best practice not to place multiple lines of business logic in the try body

Actually I'd say it is. You usually want to catch all exceptions from working with the value:

try {
const createdUser = await this.User.create(userInfo);

console.log(createdUser)
// business logic goes here
} catch (error) {
console.error(error) // from creation or business logic
}

If you want to catch and handle errors only from the promise, you have three choices:

  • Declare the variable outside, and branch depending on whether there was an exception or not. That can take various forms, like

    • assign a default value to the variable in the catch block
    • return early or re-throw an exception from the catch block
    • set a flag whether the catch block caught an exception, and test for it in an if condition
    • test for the value of the variable to have been assigned
      let createdUser; // or use `var` inside the block
    try {
    createdUser = await this.User.create(userInfo);
    } catch (error) {
    console.error(error) // from creation
    }
    if (createdUser) { // user was successfully created
    console.log(createdUser)
    // business logic goes here
    }
  • Test the caught exception for its type, and handle or rethrow it based on that.

      try {
    const createdUser = await this.User.create(userInfo);
    // user was successfully created
    console.log(createdUser)
    // business logic goes here
    } catch (error) {
    if (error instanceof CreationError) {
    console.error(error) // from creation
    } else {
    throw error;
    }
    }

    Unfortunately, standard JavaScript (still) doesn't have syntax support for conditional exceptions.

    If your method doesn't return promises that are rejected with specific enough errors, you can do that yourself by re-throwing something more appropriate in a .catch() handler:

      try {
    const createdUser = await this.User.create(userInfo).catch(err => {
    throw new CreationError(err.message, {code: "USER_CREATE"});
    });

    } …

    See also Handling multiple catches in promise chain for the pre-async/await version of this.

  • Use then with two callbacks instead of try/catch. This really is the least ugly way and my personal recommendation also for its simplicity and correctness, not relying on tagged errors or looks of the result value to distinguish between fulfillment and rejection of the promise:

      await this.User.create(userInfo).then(createdUser => {
    // user was successfully created
    console.log(createdUser)
    // business logic goes here
    }, error => {
    console.error(error) // from creation
    });

    Of course it comes with the drawback of introducing callback functions, meaning you cannot as easily break/continue loops or do early returns from the outer function.

try/catch blocks with async/await

Alternatives

An alternative to this:

async function main() {
try {
var quote = await getQuote();
console.log(quote);
} catch (error) {
console.error(error);
}
}

would be something like this, using promises explicitly:

function main() {
getQuote().then((quote) => {
console.log(quote);
}).catch((error) => {
console.error(error);
});
}

or something like this, using continuation passing style:

function main() {
getQuote((error, quote) => {
if (error) {
console.error(error);
} else {
console.log(quote);
}
});
}

Original example

What your original code does is suspend the execution and wait for the promise returned by getQuote() to settle. It then continues the execution and writes the returned value to var quote and then prints it if the promise was resolved, or throws an exception and runs the catch block that prints the error if the promise was rejected.

You can do the same thing using the Promise API directly like in the second example.

Performance

Now, for the performance. Let's test it!

I just wrote this code - f1() gives 1 as a return value, f2() throws 1 as an exception:

function f1() {
return 1;
}

function f2() {
throw 1;
}

Now let's call the same code million times, first with f1():

var sum = 0;
for (var i = 0; i < 1e6; i++) {
try {
sum += f1();
} catch (e) {
sum += e;
}
}
console.log(sum);

And then let's change f1() to f2():

var sum = 0;
for (var i = 0; i < 1e6; i++) {
try {
sum += f2();
} catch (e) {
sum += e;
}
}
console.log(sum);

This is the result I got for f1:

$ time node throw-test.js 
1000000

real 0m0.073s
user 0m0.070s
sys 0m0.004s

This is what I got for f2:

$ time node throw-test.js 
1000000

real 0m0.632s
user 0m0.629s
sys 0m0.004s

It seems that you can do something like 2 million throws a second in one single-threaded process. If you're doing more than that then you may need to worry about it.

Summary

I wouldn't worry about things like that in Node. If things like that get used a lot then it will get optimized eventually by the V8 or SpiderMonkey or Chakra teams and everyone will follow - it's not like it's not optimized as a principle, it's just not a problem.

Even if it isn't optimized then I'd still argue that if you're maxing out your CPU in Node then you should probably write your number crunching in C - that's what the native addons are for, among other things. Or maybe things like node.native would be better suited for the job than Node.js.

I'm wondering what would be a use case that needs throwing so many exceptions. Usually throwing an exception instead of returning a value is, well, an exception.

Issue with try catch in async await

You can refactor your code in smaller functions that return a promise for which you can locally wrap try-catch and handle it.

async function executeJob(job) {

// necessary variable declaration code here
try {

await doProcedure();

providerNPIIds = [...providerNPIIds];

// Fetch provider details
let providerDetails = await esHelper.getProvidersById(providerNPIIds, true);
const updateProviderCount = await getProviderCount(userId, providerNPIIds, providerCountType);

if(updateProviderCount) {
await destroyJobById(job.idd);
}

executeNextJob();
} catch (e) {
if(e instanceof QueueError) {
console.log('Exiting from process');
process.exit(1);
} else {
console.log('Working Code');
buryFailedJobAndExecuteNext(job);
}
}
}

async function doProcedure() {
try {
do {
let procedureRequests = await ProcedureRequestModel.find(filter, options);

// doing process here...

} while (fetchedCount < totalCount);
} catch (err) {
throw err;
}
}

async function getProviderCount(userId, providerNPIIds, providerCountType) {
try {
let updateProviderCount = await UserProvider.updateAll({ userId: userId }, { providers: providerNPIIds, countByType: providerCountType });
return updateProviderCount;
} catch (err) {
logger.error('Failed to update UserProviders & Count: %O', err);
throw e;
}
}

async function destroyJobById(Id) {
try {
let destroyJobId = await app.models.Job.destroyById(Id);
} catch (err) {
throw err;
}
}

Why is try {} .. catch() not working with async/await function?

You need to await errorTest

const callFunction=async()=>{
try{
const result = await errorTest()
}catch(err){
console.log(err)
}
}
callFunction ()

Note that the await errorTest() function has to also be in an async function. That's why I put it inside callFunction ()

Another Option

const errorTest = async() => { 
try{
const result = await $.get("http://dataa.fixer.io/api/latest?access_key=9790286e305d82fbde77cc1948cf847c&format=1");

console.log(result)
}catch(err){
console.log(err)
}
}

Handling HTTP error with async await and try and catch clause in react typescript

As you can see from the Fetch docs:

The Promise returned from fetch() won’t reject on HTTP error status
even if the response is an HTTP 404 or 500. Instead [...] the Promise
will resolve normally (with the ok property of the response set to
false if the response isn’t in the range 200–299)

So the catch clause in fetchMoviesHandler doesn't get immediately executed when you get the 404 response, it only executes when you try to parse the body from the response (const data = await response.json()), as there's no json to parse there. That's when the error is actually thrown and catched, but then there's no Message property on it, so nothing to show: the property on the built-in error object is message.

In order to handle this situation you should check for the ok property in the HTTP response and throw a specific error. Something like this:

async function fetchMoviesHandler() {
setIsLoading(true);
setError(null);
try {
const response = await fetch('https://swapi.dev/api/film/');
if (!response.ok) {
throw new Error('Something went wrong');
}
const data = await response.json();
const transformedMovies = data.results.map((movieData: any) => {
return {
id: movieData.episode_id,
title: movieData.title,
openingText: movieData.opening_crawl,
releaseDate: movieData.release_date,
};
});
setMovies(transformedMovies);
} catch (err: any) {
setError(err.message);
console.log(err);
}
setIsLoading(false);
}

async/await + try/catch not working as spected when using a .then() function

What is the idea beneath mixing approach?

This should work

class Registro extends Component {
render() {
if (this.state.redirect) {
return <Navigate to={this.state.redirect} />;
}

return (
<button
id="submit"
className="btn btn-outline-accesible col-3 m-2 mt-3"
onClick={this.handleClick}
>
Acceder
</button>
);
}

handleClick = async () => {
try {
await registerWithEmailAndPassword(
this.state.userName,
this.state.email,
this.state.password
);
handleRedirect();
} catch (err) {
console.error(err);
alert(err.message);
}
};
}

const registerWithEmailAndPassword = async (name, email, password) => {
console.log(name, email, password);
const res = await createUserWithEmailAndPassword(auth, email, password);
const user = res.user;
await setDoc(doc(db, "users", email), {
email: email,
nombre: name,
pass: password,
});
alert("Registro completado con éxito");
};

UPDATE:
Please note that registerWithEmailAndPassword also updated to support correct error handling according to the request



Related Topics



Leave a reply



Submit