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 thecatch
block- set a flag whether the
catch
block caught an exception, and test for it in anif
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
}- assign a default value to the variable in the
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 oftry
/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 earlyreturn
s 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
Waiting For More Than One Concurrent Await Operation
JavaScript Inheritance and the Constructor Property
How Does This Object Method Definition Work Without the "Function" Keyword
Curly Brackets in Arrow Functions
How to Use JavaScript Conditionally Like CSS3 Media Queries, Orientation
Polymer Share Styles Across Elements
Unable to Scroll in Scrollview
JavaScript Console.Log() in an iOS Uiwebview
Why Can't I Access a Property of an Integer with a Single Dot
Prevent Browser Caching of Ajax Call Result
Managing Jquery Plugin Dependency in Webpack
Merge Two Array of Objects Based on a Key
How to Use Backslashes (\) in a String
Best Way to Find If an Item Is in a JavaScript Array
Programmatically Changing Webkit-Transformation Values in Animation Rules
How to Preserve Aspect Ratio When Scaling Image Using One (Css) Dimension in IE6