Please take a look at this JavaScript code example demonstrating try-catch code. Its purpose is to be a simple example to a try-catch code, to learn the concept.
let age = prompt(`Please enter your age, `));
let err1 = `Error: Make sure field isn't empty and only a number is given`;
let err2 = `Error: Age out of range`;
try (
if (age == "" || isNaN(age)) {
throw err1;
} else if (age < 0 || age > 120) {
throw err2;
}
)
catch (error) {
if (error == err1) {
console.log('Age was either empty or non solely numerical.');
} else if (error == err2) {
console.log('A solely numerical age was given, but it was beyond range.');
}
exit;
}
From the example I can assume that the main reason for using try-catch codes is to better organize the code (especially, better organizing the outcome of each error), even though we could achieve its exact results without try and catch, and in a more imperative code (the outcome of each error would be defined in row for example, instead later in a catch block).
Is better organization of the code (especially, custom error handling) the main reason to combine these two blocks in our codes?
The main advantage of using a try{} catch(exception){} is that you're able to shift control to the catch(exception){} in the event that an exception is thrown, which allows you to continue processing, as opposed to your script failing miserably. In short, you're catching the exception.
In other words, the main reason is to catch an exception, and then decide what action you'd like to take. Is it possible that you can you approach the problem in a different way and complete the task without failing? If so, that's where catch(exception){ // do something different } comes into play. In a manner of speaking, it offers you a second chance :-)
The main reason for try catch is to stop errors from crashing your programm. In this example if the user gives an age thats not a number and you try to process it later on in your code might crash or not work as intended.
Related
Here is my scenario:
I am creating a user object which I am saving to my database. After this I am doing something else which may result in an error. If so, I need to "rollback" the changes I made to the database, meaning I have to delete the user object from the database again in the catch block. However, this delete action may also fail meaning I need to know how I handle this?
When I say "handle" what I mean is I would like to save the error to my database. So I want the original error to be saved and also the error in the case the deleting fails. (I also know saving the error to the database might fail, but if it does there isnt much I can do so I'll just let it happen)
So do I need to use a nested try-catch inside the catch block? or will the catch block "catch" its own errors?
// psuedocode-ish illustation of what I'm working with
try {
const new_user = Database.save(user);
MoreCodeThatMightThrowAnError(); // imagine this throws an error
}
catch (error) {
if (new_user) Database.delete(user); // Do I need this inside a nested try-catch?
console.log(error);
Database.save(error); // dont care if this fails
}
Also, this is just a simplified example of what I am doing so I cannot just move the MoreCodeThatMightThrowAnError() up or use some build in rollback functionality from my database unfortunantly.
You are correct, you need to use another try-catch block. Even though it' seems a bit strange, it's sometimes unavoidable. See this question for more.
I would suggest organizing your code like this:
// psuedocode representation
try {
const new_user = Database.save(user);
try {
const otherCode = Database.otherThingThatCauseError();
} catch(err) {
console.log(err)
}
// ... and so on
} catch(err) {
// no need to rollback, most databases are ACID-compliant
console.log(err);
So basically, you would want to add another try, catch block. I believe that you won't have to rollback your changes since databases are ACID compliant, so if something wrong happens in the middle of an operation (i.e. creating a new user), the database will automatically roll back the whole operation.
A catch block does not catch errors that occur inside of it, so you would need to use a nested try...catch statement.
try {
const new_user = Database.save(user);
MoreCodeThatMightThrowAnError(); // imagine this throws an error
}
catch (error) {
console.log(error);
try {
if (new_user) Database.delete(user);
} catch (error2) {
console.log(error2);
try {
Database.save(error2);
} catch (error3) {}
}
}
I'm a JS game dev who's been trying to combat tampermonkey scripts for a while now.
I came up with a solution for people hooking into WebSockets where I'd cause the WebSocket to throw an error new WebSocket(0); (0 throws an error due to it being a number)
let output;
try {
output = new target(...args);
} catch(e) {
let source = e.stack.substring(e.stack.indexOf("("), 1 + e.stack.indexOf(")"));
e.stack = e.stack.replace(source, "nothing to see here");
throw e;
}
this code made the error's stack have all the information I was looking for replaced!
I've been looking at Object.defineProperty, and I was wondering how I could stop an error's stack from being modified before I have access to that specific error. And if anyone has any other ways I could stop a script from being loaded or run, I'd love to hear them!
One thing you could do is Object.freeze the error before throwing it. This would prevent people from altering the object's contents.
So for example:
try {
new WebSocket(0);
} catch (wsErr) {
throw Object.freeze(wsErr);
}
The code catching your error and trying to alter it would fail to be able to alter it. This should work as it will cause the code that was altering the error to throw with the following:
Cannot assign to read only property 'stack' of object ''
The other thing you'll have to consider is that in your code where you're catching the error, you will not be able to alter its contents either. Typically with errors, that's not a huge deal though. Tampering with errors is one of the only reasons I can think of for modifying the error.
UPDATE
[Rewriting question to focus on the problem I am trying to understand.]
Is there a means in JavaScript to throw Exceptions that notify the line number where the problem occurs? Similar to C#'s debugger, if an error is thrown on line 50 then I will be taken to line 50.
For example, according to MDN EvalError represents an error with eval(). So, let's say I have a function that uses eval(). I want to use a specific error that is representative of the problem at hand, EvalError:
//As written here the error implies there is a problem on this line. See Firebug console window
var evalErra = new EvalError('required element missing from evaluation');
var stringFunc = "a=2;y=3;document.write(x*y);";
EvalString(stringFunc);
function EvalString(stringObject) {
//Some arbitrary check, for arguments sake let's say checking for 'x' makes this eval() valid.
if(stringObject.indexOf('x') !== -1) {
throw evalErra;
//throw 'required element missing from evaluation';//This way offers no line number
}
eval(stringFunc);//The problem really lies in the context of this function.
}
If I'm going about this all wrong, then please tell me how I should approach these kinds of issues.
When you throw an error, execution of the current code will stop and JS will work its way back up the execution tree until it finds a catch () which handles the particular type of error being thrown, or gets all the way up to the top of the tree, causing an "unhandled exception" error: You threw an error, and nothing caught it, and now someone's window got broken.
try {
if (true) {
throw 'yup'
}
} catch (e) { // catches all errors
... handle the error
}
When doing error handling you want to do the following
throw new Error("message");
Then if you ever handle this error look at err.stack (firefox/opera/chrome) or err.line (Safari) or err.IE_Y_U_NO_SHOW_ME_ERROR_LINE_NUMBER (IE) to find the line number.
If you want you can subclass Error.
ok, I feel stupid asking this question, and forgive my poor research techniques, but...
using the example
if( obj.attr1.attr2.attr3 == 'constant' ) return;
else if( condition2 ) ...
if obj.attr1 is undefined, the javascript engine throws an error.
what is the error that is thrown? is it universally defined?
is is possible to globally trap this error?
if trapped, is it possible for the next line condition2 to be executed?
to clarify: the error is raised because trying to get attribute of undefined. is there any way to know that this is the error being raised? is it in some table of standard javascript error messages?
and second, having trapped the error upstream, is it possible for program to flow uninterruptedly?
It's possible to trap this error with a try/catch block:
try{
if( obj.attr1.attr2.attr3 == 'constant' ) {
alert("test");
}
}
catch(e)
{
alert(e.Message);
}
The exception gives you the following:
description "'obj' is undefined" String
message "'obj' is undefined" String
name "TypeError" String
number -2146823279 Number
Usually this is solved gracefully by not blindly assuming that something is there.
if( obj.attr1 && obj.attr1.attr2 && obj.attr1.attr2.attr3 == 'constant' )
Other than that, you can write a try/catch statement that catches the exception here, but using structured exception handling to direct the normal program flow is frowned upon and should be avoided.
OK. I may be splitting hairs here, but my code isn't consistent and I'd like to make it so. But before I do, I want to make sure I'm going the right way. In practice this doesn't matter, but this has been bothering me for a while so I figured I'd ask my peers...
Every time I use a try... catch statement, in the catch block I always log a message to my internal console. However my log messages are not consistent. They either look like:
catch(err) {
DFTools.console.log("someMethod caught an error: ",err.message);
...
or:
catch(ex) {
DFTools.console.log("someMethod caught an exception: ",ex.message);
...
Obviously the code functions properly either way but it's starting to bother me that I sometimes refer to "errors" and sometimes to "exceptions". Like I said, maybe I'm splitting hairs but which is the proper terminology? "Exception", or "Error"?
This is a bit subjective, but to me an error is when someone or something does something wrong, improper, or invalid. It could be a syntax error, a logical error, a read error, user error, or even a social error. It's an abstract concept.
An exception, on the other hand, is an object that is created and thrown when a certain condition occurs in code. It may or may not correspond to a conceptual error. So to me, the proper nomenclature is "exception".
The ECMAScript specification calls them exceptions. You might want to do likewise.
To make your logging more informative:
catch(ex) {
DFTools.console.log("someMethod caught an exception of type "
+ ex.name + ": ", ex.message);
You might also want to bear in mind that exceptions (unfortunately) can be of any type, and so don't necessarily have name and message properties:
catch(ex) {
if (ex.message && ex.name) {
DFTools.console.log("someMethod caught an exception of type "
+ ex.name + ": ", ex.message);
} else /* deal with it somehow */
As this is starting to look pretty cumbersome to repeat everywhere, you might want to capture it in a function:
function logExceptions(methodName, action) {
try {
action();
} catch (ex) {
if (ex.message && ex.name) {
DFTools.console.log("someMethod caught an exception of type "
+ ex.name + ": ", ex.message);
} else {
DFTools.console.log("someMethod caught a poorly-typed exception: " + ex);
}
}
}
Now you can say:
logExceptions(function() {
// do some risky stuff...
});
In JavaScript it is called Error Catching. So I would suggest you use error instead of exception.
Leave the choice in the middle by using "e". Like in the examples of Mozilla.
Mozilla Core JavaScript 1.5 Reference
Exception is something you may expected for example in an attempt to open a file may face a "File not found exception". On the other hand, errors are something you may not see it coming like stack over flow or not enough memory.
An exception is an alternative logical way out off a function that does not produce a logical result. An exception also allows a better explanation of what happen why it exist this way. For File opening, again, a file handle is a logical result and if the file is not exist (one possible exception) or it is a folder not a file (another possible exception).
MAJOR DISCLAIMER: I don't consider that there is a "right" answer to this. The views expressed here are subjective and personal. What's more is that the ideas I'm about to espouse are only useful if you are going to do different things with different, ahem, faults... as you might using a system as per Daniel Earwicker's informative answer. With that in mind:
I contend that "an EXCEPTION is exceptional". An ERROR is less unexpected.
disclaimer: The following pseudo-code is not good; it merely serves as the minimum case I could think of to illustrate my point.
note: in this thought experiment, GetFile returns UNDEFINED if it cannot find the specified file.
function AlwaysGetFile(name){
var file = null;
if(FileExists(name)){
file = GetFile(name);
if(typeof file === "undefined"){
throw new "couldn't retrieve file" EXCEPTION
}
}
else{
throw new "file does not exist" ERROR
}
return file;
}
In the case that a consumer calls GetFileOrThrow with a filename that doesn't exist, an ERROR will occur. To my mind the distinction is really that higher-level code (or user input) is doing something wrong... this function must pass an ERROR up the line to that higher-level code which can decide what to do about this result. Consider it like this... this function would be saying to any consuming functions:
Look, my friend, I know what's going on here: it is an ERROR to request BobAccounts.xml, so don't do it again! Oh, and if you think you now know what might have gone wrong (having abused me), go ahead and try to recover from it!
Now consider the case that this function takes the name, checks that the file exists and then for some reason fails to retrieve it. This is a different situation. Something really unexpected has happened. What's more, the consuming code isn't to blame. Now we really want this function to say to any consuming functions:
Oh fiddlesticks! Sorry about this, I humbly beg your pardon but something EXCEPTIONAL that I don't really understand has gone wrong. I don't think that your request for BobAccounts.xml was unreasonable... and I know I should be fulfilling it for you. Since I'm lower level code than you, I really ought to know what's going on... but I don't... and since you've less chance than me of understanding this EXCEPTIONAL situation, I think you'd probably best just stop what you're doing and let this message go all the way to the top... I mean, there is something seriously fishy going on here.
So I suppose my summary is this: If the mistake happened in higher order code (you were passed bad data) throw an ERROR. If the mistake happened in lower order code (a function you depended on failed in a way you didn't understand and couldn't plan for) throw an EXCEPTION... and if the mistake happened in the function you are currently writing... well, duh, if you're aware of it then fix it!
And, finally, to answer the original question more directly: In terms of handling ERRORS and EXCEPTIONS, my advice would be: Handle all ERRORS gracefully (optionally logging them)... but handle EXCEPTIONS carefully indeed; only try to recover from an EXCEPTION if you are really sure you know what it is and why it's happened, otherwise let it bubble up (rethrowing it if you have to).
What you get in a Catch block is an Exception, so I name it as an exception...
If it is an error - I can handle it in my code & I usually don't expect to see it in the Catch block
HTH.