Try catch is used to catch errors and report to user. all said and fine. But where exactly one has to put the try-catch. Or What exactly has to go inside try catch on a usual basis.
Most importantly, is it absolutely a good coding practice to have a try catch block?
I think it is good practce to use a try catch if it will handle errors and prevent the program from crashing.
Taken from W3 Schools:
The try statement lets you test a block of code for errors.
The catch statement lets you handle the error.
The throw statement lets you create custom errors.
The finally statement lets you execute
code, after try and catch, regardless of the result.
An example:
fuction foo()
{
try
{
// Block of code to try
}
catch(e)
{
// Block of code to handle errors
document.getElementById("demo").innerHTML = e.message;
}
finally
{
// Block of code to be executed regardless of the try / catch result
}
}
Here is soem more documentation at W3 Schools: http://www.w3schools.com/js/js_errors.asp
Yes, it absolutely good practice to use try-catch blocks. Here's a rather simplistic (but contrived) demonstration.
function safeParseJSON(json) {
try {
return JSON.parse(json);
} catch(exception) {
// could not parse this JSON
console.error(exception);
} finally {
return null;
}
}
Parsing JSON is the most common scenario I have encountered for using the try-catch construct, hence the example.
However, the usual try-catch mechanism doesn't work when the function is asynchronous. It's essential to understand this if you are ever using a server side Javascript platform.
The standard pattern for async event handling is as follows.
db.connect(options, function connected(err, client) {
if(err) throw err;
client.query(...);
});
Because that callback function is run somewhere else (presumably when the database connects) we can't wrap it with a try-catch block. Instead, most async method calls will pass the error as the first argument to the callback.
This way we can handle the error as and when it happens. If there is no error, null will be passed as the first argument, so that it can be ignored.
A number of implementations of promises try to recreate this mechanism, but in an asynchronous way.
Here's an example with Q:
db.connect(options)
.then(function(client) {
client.query(...);
})
.catch(function (error) {
throw error;
})
.fin(function() {
// finally
db.close();
});
You can also use Q on the client side, if you are working with asynchronous functions.
Related
I am using try catch inside try block to print relative message or get to know in which method error happened.
code snippet
for (const searchUrl of savedSearchUrls) {
console.log("here");
// function will get all the links of profiles in saved search url
try {
const links = await scrapeFromurl(browser, searchUrl);
try {
saveToDatabase(links);
} catch (e) {
handleError(e, "eror while saving to database");
}
} catch (err) {
handleError(err, "error in scrapeFromurl()");
}
}
I have searched on google but couldn't find related topic.
what are the other ways to accomplish similar things?
what are the best practice to handle this type of situation.
I would suggest using only one try catch block and specific error instances for each method, then in catch block you can simply check which method throws an error by using instanceof operator
class ScrapeError extends Error {
message = "error in scrapeFromurl()"
}
class DBError extends Error {
message = "eror while saving to database"
}
async function scrapeFromurl() {
throw new ScrapeError();
}
async function saveToDatabase(links) {
throw new DBError();
}
async function main() {
try {
const links = await scrapeFromurl();
await saveToDatabase(links);
} catch (e) {
if (e instanceof ScrapeError) {
console.log('scrape', e);
}
if (e instanceof DBError) {
console.log('dberror', e);
}
}
}
main();
By default a single try-catch block is enough without needs for nesting other try-catches into it. However, there may be some legitimate exceptions from these rules.
Exception 1: Different handlers for the same exception
Let's consider the following example
try {
myroutine(); // may throw three types of exceptions
} catch (e) {
if (e instanceof TypeError) {
// statements to handle TypeError exceptions
} else if (e instanceof RangeError) {
// statements to handle RangeError exceptions
} else if (e instanceof EvalError) {
// statements to handle EvalError exceptions
} else {
// statements to handle any unspecified exceptions
logMyErrors(e); // pass exception object to error handler
}
}
It is perfectly possible that inside your try there is a section where a given error type, like a RangeError needs a different way of handling than the main catch. In this case it might make sense to have another try-catch inside your try, albeit, in this case, for better readability it would make sense to consider the inner try as a method and call that, so you would not physically nest the try-catch blocks, but separate the concerns of the try-catches into separate methods.
Exception 2: Handling a certain type of error only at a section of a try-block
It is quite possible that you want your try-catch to throw the error further in the majority of your try block, but, in a specific section you want it to handle it. Again, in this case it would make sense to separate the inner try into its own method.
Conclusion
Having nested try-catches are nonintuitive for a reader, therefore it makes sense to separate the inner try into its own method whenever you encounter the need to nest tries. Yet, as the examples above show, there are legitimate needs to drift away from the outer handling of an error for some sections. However, by default it is a good idea to consider such sections as separate concerns worthy of separating from the method. Of course, sometimes you might want to keep nested try-catches without separating their concerns, but more often than not it is worth to apply the separations. So, a rule of thumb that you may want to consider is to refactor nested try-catches either into separate methods or a single try-catch, unless there is a very good reason not to do so.
In asyncronous scripts you can use domains for error handling. And trycatch in trycatch can be treated like domain in domain, which is pointless.
Moreover, programmers always tend to prevent the code from growing horizontally like this
{
...
{
...
{
... (and so on)
{
}
}
}
}
So it is a really bad idea. I can keep on telling drawbacks of this approach, but not going to. Just use one trycatch with switchcase inside to handle all errors
I'm still learning the language, and I'm very curious to know what is the proper way to ensure that either all functions will execute or none when one action requires series of functions to be executed. For example I might have an HTML button that calls some apply() function:
function apply() {
try {
// Check arguments, choose what exactly to do next through some IFs etc...
}
anotherFunction();
}
function anotherFunction() {
try {
// Request data from DB, process data received, update object variables, etc...
}
yetAnotherFunction();
}
function yetAnotherFunction() {
try {
// Update HTML
}
oneMoreFunction();
}
function oneMoreFunction() {
try {
// Update graph
}
}
So the problem here is that if any of the functions in the flow throws an error the rest functions won't do what they should, hence the entire Apply process will be interrupted with some changes applied (let's say HTML is getting updated) but the rest (the graph) is not. I'm curious to know what is the best practice to prevent this behaviour? Yes I'm trying my best to use try {} and check arguments for errors etc, but it looks like I can't foresee everything, I just need some way to tell the code "ensure you can execute all of the functions, in case of any errors, just don't do anything at all". Please advise what can be done here?
You're taking the right path when thinking about try/catch blocks, but notice I used a 'catch' as well. Usually (maybe that is even enforced, I can't remember) you need the catch blocks along with the try.
So your functions could look something like this:
function async myFirstTryCatch() {
try {
// Make your request in the try block
await requestCall();
} catch(error){
// Hey, my http call returned an error
// Deal with the error here. Maybe show a toast, validate a form
// Anything you need to not break the code and have good UX
console.log(error)
}
}
In that same line of thought, you could have each function handle their own try/catch or maybe control that in your apply function, in case some of the chain must continue/stop depending each other.
function apply() {
try {
firstCall();
functionThatRequiresFirstCalltoSucceed();
} catch (error){
//Will catch if either firstCall or functionThatRequiresFirstCalltoSucceed fail
console.log(error)
}
functionThatIndependsFromTheResultAbove();
}
I hope this will help you build your thoughts about error handling in JS :)
IMPORTANT NOTE
If your code enters the catch block, it will consider that the error has been dealt with and will not propagate! Here's an example
function functionThatThrowsError(){
try{
throw new Error('Example Error!');
} catch (error) {
// Error has been dealt with
console.log(error) // Returns "Example Error"
// throw error; <--- Throw the error in the catch block if you need t to propagate
}
}
function wontCatchError() {
try {
functionThatThrowsError();
} catch (error) {
// THE CODE WILL NOT ENTER THE CATCH BLOCK
// SINCE THE ERROR WAS CAUGHT IN THE FUNCTION ITSELF.
// If you need to catch here as well, make sure to throw the error
// in the catch block of the 'functionThatThrowsError'
console.log(error)
}
}
We use AWS Lambda for the backend of our mobile application. I just realized that our uncaught exceptions were not being logged correctly so we could be alerted to them. I realize that we could use something like this
process.on('uncaughtException', (err) => {
console.log(...)
process.exit(1) //mandatory (as per the Node docs)
})
This has a lot of problems though as I do not believe we could push the error into our SNS log stream. Ideally, we'd like to put a try catch block around some of our main processing code, but this does not work as its getting called asynchronously and it does not get caught
async.waterfall([
async.apply(verifyCacheIsReady, request_data),
async.apply(verifyRequestAndGetUser, request_data),
async.apply(logSession, request_data)],
function (command_callback)
{
},
function(err)
{
}
I realize I could try catch in all of this functions, but this is a simplified version. Is there a good way to catch something that happens in this block of code?
In this function that handles a REST API call, any of the called functions to handle parts of the request might throw an error to signal that an error code should be sent as response. However, the function itself might also discover an error, at which point it should jump into the exception handling block.
static async handleRequest(req) {
try {
let isAllowed = await checkIfIsAllowed(req);
if (!isAllowed) {
throw new ForbiddenException("You're not allowed to do that.");
}
let result = await doSomething(req); // can also raise exceptions
sendResult(result);
} catch(err) {
sendErrorCode(err);
}
}
Webstorm will underline the throw with the following message: 'throw' of exception caught locally. This inspection reports any instances of JavaScript throw statements whose exceptions are always caught by containing try statements. Using throw statements as a "goto" to change the local flow of control is likely to be confusing.
However, I'm not sure how to refactor the code to improve the situation.
I could copypaste the code from the catch block into the if check, but I believe this would make my code less readable and harder to maintain.
I could write a new function that does the isAllowed check and throws an exception if it doesn't succeed, but that seems to be sidestepping the issue, rather than fixing a design problem that Webstorm is supposedly reporting.
Are we using exceptions in a bad way, and that's why we're encountering this problem, or is the Webstorm error simply misguiding and should be disabled?
Contrary to James Thorpe's opinion, I slightly prefer the pattern of throwing. I don't see any compelling reason to treat local errors in the try block any differently from errors that bubble up from deeper in the call stack... just throw them. In my opinion, this is a better application of consistency.
Because this pattern is more consistent, it naturally lends itself better to refactoring when you want to extract logic in the try block to another function that is perhaps in another module/file.
// main.js
try {
if (!data) throw Error('missing data')
} catch (error) {
handleError(error)
}
// Refactor...
// validate.js
function checkData(data) {
if (!data) throw Error('missing data')
}
// main.js
try {
checkData(data)
} catch (error) {
handleError(error)
}
If instead of throwing in the try block you handle the error, then the logic has to change if you refactor it outside of the try block.
In addition, handling the error has the drawback of making you remember to return early so that the try block doesn't continue to execute logic after the error is encountered. This can be quite easy to forget.
try {
if (!data) {
handleError(error)
return // if you forget this, you might execute code you didn't mean to. this isn't a problem with throw.
}
// more logic down here
} catch (error) {
handleError(error)
}
If you're concerned about which method is more performant, you shouldn't be. Handling the error is technically more performant, but the difference between the two is absolutely trivial.
Consider the possibility that WebStorm is a bit too opinionated here. ESLint doesn't even have a rule for this. Either pattern is completely valid.
You're checking for something and throwing an exception if isAllowed fails, but you know what to do in that situation - call sendErrorCode. You should throw exceptions to external callers if you don't know how to handle the situation - ie in exceptional circumstances.
In this case you already have a defined process of what to do if this happens - just use it directly without the indirect throw/catch:
static async handleRequest(req) {
try {
let isAllowed = await checkIfIsAllowed(req);
if (!isAllowed) {
sendErrorCode("You're not allowed to do that.");
return;
}
let result = await doSomething(req); // can also raise exceptions
sendResult(result);
} catch(err) {
sendErrorCode(err);
}
}
I could copypaste the code from the catch block into the ifcheck, but I believe this would make my code less readable and harder to maintain.
On the contrary, as above, I would expect this to be the way to handle this situation.
Since this is not a blocking error, but only an IDE recommendation, then the question should be viewed from two sides.
The first side is performance. If this is a bottleneck and it is potentially possible to use it with compilation or when transferring to new (not yet released) versions of nodejs, the presence of repetitions is not always a bad solution. It seems that the IDE hints precisely in this case and that such a design can lead to poor optimization in some cases.
The second side is the code design. If it will make the code more readable and simplify the work for other developers - keep it. From this point of view, solutions have already been proposed above.
Return a promise reject instead of throwing error in the try block
try {
const isAllowed = await checkIfIsAllowed(request);
if (!isAllowed) {
return Promise.reject(Error("You're not allowed to do that."));
}
const result = await doSomething(request);
sendResult(result);
} catch (error) {
throw error;
}
There are good answers to the question "Why not use exceptions as normal flow control?" here.
The reason not to throw an exception that you will catch locally is that you locally know how to handle that situation, so it is, by definition, not exceptional.
#James Thorpe's answer looks good to me, but #matchish feels it violates DRY. I say that in general, it does not. DRY, which stands for Don't Repeat Yourself, is defined by the people who coined the phrase as "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system". As applied to writing software code, it is about not repeating complex code.
Practically any code that is said to violate DRY is said to be "fixed" by extracting the repeated code into a function and then calling that function from the places it was previously repeated. Having multiple parts of your code call sendErrorCode is the solution to fixing a DRY problem. All of the knowledge of what to do with the error is in one definitive place, namely the sendErrorCode function.
I would modify #James Thorpe's answer slightly, but it is more of a quibble than a real criticism, which is that sendErrorCode should be receiving exception objects or strings but not both:
static async handleRequest(req) {
try {
let isAllowed = await checkIfIsAllowed(req);
if (!isAllowed) {
sendErrorCode(new ForbiddenException("You're not allowed to do that."));
return;
}
let result = await doSomething(req); // can also raise exceptions
sendResult(result);
} catch(err) {
sendErrorCode(err);
}
}
The larger question is what is the likelihood of the error and is it appropriate to treat !isAllowed as an exception. Exceptions are meant to handle unusual or unpredictable situations. I would expect !isAllowed to be a normal occurrence that should be handled with logic specific to that situation, unlike, say, a sudden inability to query the database that has the answer to the isAllowed question.
#matchish's proposed solution changes the contract of doSomethingOnAllowedRequest from something that will never throw an exception to something that will routinely throw an exception, placing the burden of exception handling on all of its callers. This is likely to cause a violation of DRY by causing multiple callers to have repetitions of the same error handling code, so in the abstract I do not like it. In practice, it would depend on the overall situation, such as how many callers are there and do they, in fact, share the same response to errors.
Answer of James Thorpe has one disadvantage on my opinion. It's not DRY, in both cases when you call sendError you handle Exceptions. Let's imagine we have many lines of code with logic like this where Exception can be thrown. I think it can be better.
This is my solution
async function doSomethingOnAllowedRequest(req) {
let isAllowed = await checkIfIsAllowed(req);
if (!isAllowed) {
throw new ForbiddenException("You're not allowed to do that.");
}
doSomething(req);
}
static async handleRequest(req) {
try {
let result = await doSomethingOnAllowedRequest(req);
sendResult(result);
} catch(err) {
sendErrorCode(err);
}
}
This could give you some tips, maybe that can be the cause(not sure if relevant).
Catch statement does not catch thrown error
"
The reason why your try catch block is failing is because an ajax request is asynchronous. The try catch block will execute before the Ajax call and send the request itself, but the error is thrown when the result is returned, AT A LATER POINT IN TIME.
When the try catch block is executed, there is no error. When the error is thrown, there is no try catch. If you need try catch for ajax requests, always put ajax try catch blocks inside the success callback, NEVER outside of it."
I've heard from plenty of people saying that throwing errors in Node is bad practice, and you should rather manually handle them via CommonJS's callback syntax:
somethingThatPassesAnError( function(err, value) {
if (err) console.log("ERROR: " + err);
});
Yet, I've found in multiple unit testing frameworks (Mocha, Should.js, Gently) that it seems like they want you to throw an error when something happens. I mean, sure, you can design your tests to check for equality of variables and check for not-null in error vars, but in the words of Ryan Dahl himself, "you should write your framework to make the right things easy to do and the wrong things hard to do".
So what gives? Can anyone explain why that practice exists? Should I start throwing fatal exceptions like require() would if the module couldn't be found?
It because nodejs programs typically make heavy use of async, and as a result errors are often thrown after your try/catch has already completed successfully. Consider this contrived example.
function foo(callback) {
process.nextTick(function() {
if (something) throw "error";
callback("data");
});
}
try {
foo(function(data) {
dosomething(data);
});
} catch (e) {
// "error" will not be caught here, as this code will have been executed
// before the callback returns.
}
The typical node pattern, of the first argument in a callback being an error, obviates this problem, providing a consistent way to return errors from asynchronous code.
function foo(callback) {
process.nextTick(function() {
if (something) return callback("error");
callback("data");
});
}
foo(function(error, data) {
if (error) return handleError(error);
dosomething(data);
});
It is my understanding that the case against throwing exceptions in JavaScript is due to the heavy use of asynchronous patterns. When an error occurs on another stack, you can't catch it. In those cases, use the err parameter as the first parameter for the callback.
I don't think that is the same as saying "never throw anything". If I have synchronous code, and an exception occurs, I throw it. There are differing opinions, but if callbacks aren't involved at all, I see no reason to not use throw.
I tend to follow the guidance on Joyent's Error Handling in Node.js for this one. The oversimplified gist is that there are really two types of errors (operational and programmer), and three ways to pass errors (emitting an error event on an event emitter, returning the callback with the error argument as non-null, and throwing the error).
Operational errors are errors that you expect might happen and are able to handle, ie. not necessarily bugs. Programmer errors are errors in the code itself. If you are writing code and you expect the error, then any of the patterns for passing an error are valuable. For example:
If the error happens inside an asynchronous function that accepts a callback, using the idiomatic return callback(new Error('Yadda yadda yadda')) is a correct solution (if you can't handle the error in the function).
If the error happens inside of a synchronous function and is a breaking problem (ie. the program cannot continue without the operation that was attempted) then blowing up with an uncaught thrown error is acceptable.
If the error occurs in a synchronous function but can be dealt with, then the error should be dealt with, otherwise it should be thrown, and maybe the parent function can handle it, maybe not.
Personally, I tend to only throw errors that I consider fatal, thus my code is mostly devoid of try/catch blocks (I even wrap JSON.parse in a function defined thusly: function jsonParseAsync(json, cb) { var out, err; try { out = JSON.parse(json) } catch(e) { err = e }; return cb(err, out); } ). I also try to avoid promises because they conflate promise rejection and thrown errors (even though this is getting harder to do as promises become more ubiquitous). Instead, I tend to think of synchronous functions as mathematical proofs in that if they are correct they must always be correct (thus an error in a synchronous function should break the whole program, otherwise the proof can be wrong but still usable). My error creation and checks are almost entirely assertions for bad input and emitting error events or handling asynchronous errors idiomatically.
I would suggest using exceptions to handle critical errors, much like the way require() works. If this functionality causes Node.js to misbehave, then that's a bug which I'm sure will get fixed in time.