Off The Beaten Track
It’s sad but true - error-free code is still largely a Utopian dream. No matter how careful you are, no matter how deep your knowledge or how good your IDE, you’re bound to slip up sooner or later. And when you do, and your routines decide to go AWOL, you need to take remedial action.
Most programming languages come with built-in exception handling capabilities. These exception handlers make it possible to catch errors and resolve them sensibly, thereby insulating the user from complex decisions and incomprehensible technical information. As a professional developer, you should always wrap your code in exception handling routines, if only to avoid embarrassing flameouts in front of your customers.
Up until recently, JavaScript was not one of the languages with sophisticated exception handling. Most of the time, developers were stuck with the built-in JavaScript debugger to track errors in their scripts, and had to unhappily consent to the browser taking care of errors for them in the most direct way possible - an ugly pop-up in the user’s face. All that has changed, though, with the arrival of JavaScript 1.5 (available from Internet Explorer 6.0 and Netscape 6.0), which finally allows developers to wrap their code in “try-catch” exception handlers and discreetly resolve errors internally, at the application layer itself.
That’s where this article comes in. Over the next few pages, I’m going to be looking at exception handling, with a special focus on exceptions in the JavaScript universe. I’ll be explaining the most common error types you’ll encounter, together with the JavaScript constructs you can use to catch and resolve them, and I’ll include lots of examples so that you can see how it works in practice. So come on in, and let’s get started.
Anatomy Of An Exception
Normally, when a JavaScript program encounters an error, be it syntactical or logical, it exits the program at that stage itself with a message indicating the cause of the error. Now, while this behaviour is acceptable during the development phase, it cannot continue once a program has been released to actual users. In these “live” situations, it is unprofessional to display cryptic error messages (which are usually incomprehensible to non-technical users); rather, it is more professional to intercept these errors and either resolve them (if resolution is possible), or notify the user with a clear error message (if not).
The term “exceptions” refers to those errors which can be tracked and controlled. For example, if a function attempts an unsupported operation on a built-in JavaScript object (say, trying to assign values to a non-existent array index), JavaScript will generate a “TypeError” exception, together with a message explaining the problem. Exceptions like these can be caught by the application, and appropriately diverted to an exception-handling routine.
In earlier versions of JavaScript, exception handling was almost non-existent - developers were stuck with the standard error construct provided by the browser, and had little or no control over what happened with the JavaScript interpreter encountered an error. With JavaScript 1.5, all of that changed - the language now supports standard “try-catch” exception-handling constructs, and provides a far greater degree of control over how errors are processed.
An example might make this clearer. Consider the following simple line of code,
<script language="JavaScript">
colours[2] = "red";
</script>
In the example above, JavaScript tries to change the value of the second element of the array variable “colours”. Now, this variable does not exist in the variable namespace. What does JavaScript do? Rather than quietly packing up and moving to a new neighbourhood, JavaScript decides to generate an exception.
An error has occurred in the script on this page.
Line: 8
Char: 1
Error: 'colours' is undefined
Code: 0
URL: http://localhost/errors.html
You can see this from the first few lines of the output, which describe the exception, together with the variable that caused it.
From the above output, it’s pretty clear what happened - an error occurred because the “colours” variable doesn’t exist. And JavaScript also provides primitive debugging information on the error, such as the line on which the errant code resides. A little analysis of this debug data, and you’ll quickly be able to identify the lines of code involved in the error.
Playing Catch
So that’s what an error looks like. And now that you’ve seen what makes it tick, how about writing something to handle it?
JavaScript allows you to trap errors using the standard “try-catch” exception-handling combination. Here’s what it looks like:
try {
execute this block
} catch (error) {
execute this block if error
}
Take a look at this rewrite of the previous example, which incorporates a simple exception handler.
<script language="JavaScript">
try {
colours[2] = "red";
} catch (e) {
alert("Oops! Something bad just happened. Calling 911...");
}
</script>
And this time, when the script is executed, it will not generate an error - instead, it will output
Oops! Something bad just happened. Calling 911...
This is a very basic example of how JavaScript exceptions can be trapped, and appropriate action triggered. As you will see, the ability to handle errors in a transparent manner throws open some pretty powerful possibilities…but more on that later.
The first part of the code introduces you to the “try” block; this instructs JavaScript to try - literally - to execute the statements within the enclosing block.
try {
colours[2] = "red";
}
The “catch” block sets up the exception handler, in the event that one is generated. This does the hard work of trapping the exception and suggesting how to handle it.
catch (e) {
alert("Oops! Something bad just happened. Calling 911...");
}
If an exception is generated, the “catch” segment of the code will be triggered, and JavaScript’s default error handling mechanism will be overridden by the instructions in that code segment - in this case, displaying the text “Something bad happened”.
Being Verbose
Now, what you just saw was a very primitive exception handler, albeit one which isn’t very useful on a production site. Ideally, you’d want the message generated by the exception handler to be a little more descriptive, and to contain some information on the source of the error.
JavaScript satisfies this requirement via two special, pre-defined properties of the Error object generated by an exception - the “name” and “message” properties. Take a look:
<script language="JavaScript">
try {
colours[2] = "red";
} catch (e) {
alert("An exception occurred in the script. Error name: " + e.name + ".
Error message: " + e.message);
}
</script>
Here’s the output:
An exception occurred in the script. Error name: TypeError. Error message:
'colours' is undefined
Don’t want to use the alert() box because it’s disruptive and annoying? Write the output directly to the page itself with the writeln() method instead, as below:
<script language="JavaScript">
try {
colours[2] = "red";
} catch (e) {
document.writeln("An exception occurred in the script!<br>");
document.writeln("Error name: " + e.name + "<br>");
document.writeln("Error message: " + e.message + "<br>");
}
</script>
It’s also possible to write an exception handler to ignore all errors generated in your script - the following example demonstrates:
<script language="JavaScript">
try {
// generate an error
eval("some gibberish")
} catch (e) {
// ignore it
}
</script>
In this case, it doesn’t matter what type of exception JavaScript generates - the generic handler will catch it, ignore it and continue to process the rest of the script.
It should be noted, however, that this approach, although extremely simple, is not recommended for general use. It is poor programming practice to trap all errors, regardless of type, and ignore them; it is far better - and more professional - to anticipate the likely errors ahead of time, and use the “try-catch” construct to isolate and resolve them.
All For One…
You can also write specific exception handlers for different types of exceptions, by using an “if” test to check the exception type within the “catch” block. Consider the following handler, which only handles TypeError exceptions:
<script language="JavaScript">
try {
colours[2] = "red";
} catch (e) {
if (e instanceof TypeError)
{
alert("Bad or undefined variable!");
}
}
</script>
Here’s the output:
Bad or undefined variable!
Of course, this handler will now only restrict its activities to TypeError exceptions. All other errors will be ignored.
The JavaScript 1.5 specification defines six primary error types, as follows:
EvalError - raised when the eval() functions is used in an incorrect manner;
RangeError - raised when a numeric variable exceeds its allowed range;
ReferenceError - raised when an invalid reference is used;
SyntaxError - raised when a syntax error occurs while parsing JavaScript code;
TypeError - raised when the type of a variable is not as expected;
URIError - raised when the encodeURI() or decodeURI() functions are used in an incorrect manner;
You can trap more than one exception, and handle each one in a different way, by using multiple “if” constructs within a single “catch” block.
try {
execute this block
} catch (error) {
if (error instanceOf errorType1)
{
do this
}
else if (error instanceOf errorType2)
{
do this
}
... and so on ...
else
{
do this if none of the error types above match
}
}
If an exception is encountered while running the code within the “try” block, the JavaScript interpreter stops execution of the block at that point and begins checking each “if” test within the “catch” block to see if there is a handler for the exception. If a handler is found, the code within the appropriate “if” block is executed; if not, control moves to the “else” block, if one exists.
Once the “try” block has been fully executed and assuming that the program has not been terminated, the lines following the “try” block are executed.
Take a look at the next example, which demonstrates how this works by revising the example on the previous page::
<script language="JavaScript">
// ask for user input
code = prompt("Enter some JavaScript code");
// run the code and catch errors if any generated
try {
eval(code);
} catch (e) {
if (e instanceof TypeError)
{
alert("Variable type problem, check your variable definitions!")
}
else if (e instanceof RangeError)
{
alert("Number out of range!")
}
else if (e instanceof SyntaxError)
{
alert("Syntax error in code!");
}
else
{
alert("An unspecified error occurred!");
}
}
</script>
You can test this exception handler by entering different lines of code into the box that appears when you load the page into your browser.
- To generate a TypeError, try accessing a non-existent array subscript, like this:
alert(someArr[18])
- To generate a RangeError, try creating an array with an extremely large size, like this:
var someArr = new Array(89723742304323248456)
- To generate a SyntaxError, try entering a line of code with a deliberate error in it, like this:
vara count = 99
As you will, in each case, the exception handler above will identify the error type and display an appropriate alert message. The “else” block works as a catch-all exception handler, processing all errors which have not been accounted for in the preceding “if” clauses.
The Final Solution
JavaScript also allows you to add a “finally” block to the “try-catch” block discussed previously. The “finally” block contains statements that are executed regardless of whether an exception is generated or not in the “try-catch” block.
try {
execute this block
} catch (error) {
execute this block if error
} finally {
execute this block after the try block
}
If an exception is encountered when running the code within the “try” block, JavaScript will stop execution at that point, and look for a “catch” block to handle it. Once the error has been handled (or if no “catch” block exists), control passes to the “finally” block.
Take a look at the next example to see how this works:
<script language="JavaScript">
// ask for user input
code = prompt("Enter some JavaScript code");
// run the code and catch errors if any generated
// after the error handling display goodbye message
try {
eval(code);
} catch (e) {
alert("The following error occurred: " + e.name + " - " + e.message);
} finally {
alert ("Thank you for playing. Come back soon!");
}
</script>
Here’s the output:
The following error occurred: TypeError - 'a' is undefined
Thank you for playing. Come back soon!
It’s important to note that the code in the “finally” block will be executed even if errors are encountered in the corresponding “try” block.
Raising The Bar
Thus far, you’ve been working with JavaScript’s built-in exceptions, which can handle most logical or syntactical errors. However, JavaScript also allows you to get creative with exceptions, by generating your own custom exceptions if the need arises.
This is accomplished via JavaScript’s “throw” statement, which is used to raise errors which can be detected and resolved by the “try” family of exception handlers. The “throw” statement needs to be passed an error type. When the exception is raised, this exception name and description will be made available to the defined exception handler.
Let’s go to a quick example. In the following piece of code, if the value entered into the form field is greater than 99, the code will manually generate a RangeError exception, which will be caught and displayed appropriately.
<html>
<head>
<script language="JavaScript">
function checkAge()
{
try {
// if incorrect value in form
// generate an error
if (document.forms[0].age.value > 99)
{
throw RangeError;
}
} catch (e) {
// catch all thrown errors and print error type
alert(e.name);
}
}
</script>
</head>
<body>
<form>
<input type="text" name="age" onBlur="checkAge()">
</form>
</body>
</html>
You can also create your own exceptions, via the JavaScript Error constructor. The following example demonstrates, by creating a custom error type called idiotUserError.
<script language="JavaScript">
// create new Error object
idiotUserError = new Error ("Idiot user detected, terminating...")
try {
// throw custom error
throw idiotUserError;
} catch (e) {
// then catch and display it
document.writeln(e.name);
document.writeln(e.message);
}
</script>
In this case, when you run the script, a new Error object will be created named idiotUserError, with the message specified in the Error object constructor. This error can now be thrown using the regular “throw” statement, as in the example above.
Let’s try a more useful example:
<html>
<head>
<script language="JavaScript">
// create new Error objects
badNameError = new Error ("System user name does not match actual user name");
noNameError = new Error ("System user name cannot be blank");
// create generic exception handler
// to display error message
// you may want to filter down error types
// further inside this and handle each type
// differently
function mainExceptionHandler(e)
{
alert (e.message);
}
// general form validation functions
function validateForm()
{
checkName();
}
// check form values
// if errors, throw appropriate exception
function checkName()
{
try {
if (document.forms[0].username.value == "")
{
throw noNameError;
}
if (document.forms[0].username.value != "john")
{
throw badNameError;
}
} catch (e) {
// any and all errors will go to this handler
mainExceptionHandler(e);
}
}
</script>
</head>
<body>
<form onSubmit="validateForm()">
Enter your system username: <input type="text" name="username">
<br>
<input type="submit" name="submit" value="Go">
</form>
</body>
</html>
In this case, if the value entered into the form is blank or not “john”, a custom exception will be thrown by the code. This custom exception can be caught by a generic exception handler such as the one used above, and the exception can be routed and resolved appropriately
Endzone
And that just about covers it. In this article, I took you on a guided tour of exception handling in JavaScript, demonstrating how the “try” and “catch” blocks can be used to trap and resolve errors in script execution. I showed you how to retrieve the exception type and message, write exception handlers for different error types, and even generate your own custom errors. Finally, I wrapped things up with a real-world example that demonstrated how to build a simple form validator and generate exceptions suitable for processing by a generic “try-catch” handler.
In case you’d like to learn more about these topics, you should consider visiting the following links:
The official ECMAScript reference, at http://www.ecma-international.org/publications/standards/ecma-262.htm
JavaScript 1.5 reference material in the Netscape DevEdge documentation, at http://devedge.netscape.com/library/manuals/2000/javascript/1.5/reference/stmt.html#1051663
Handling errors in Internet Explorer, at http://msdn.microsoft.com/library/en-us/dnscrpt/html/WebErrors2.asp
Until next time…be good!
Note: Examples are illustrative only, and are not meant for a production environment. Code samples in this article have been tested on Microsoft Internet Explorer 6.0. Melonfire provides no warranties or support for the source code described in this article. YMMV!
This article was first published on 08 Aug 2003.