Exception handling in JavaScript

Exception handling is a topic that may not be well-understood by some web developers, depending on what languages they have the most experience in. In particular, PHP, one of the most common server-side languages for web development, did not have support for exception handling until version 5. In the four years between the release of PHP4 and PHP5, the language became increasingly popular among developers, and as a result, a lot of code was written without exception handling in mind. The situation did not even improve much with the release of PHP5, since PHP5 was meant to be backwards-compatible with code developed for PHP4. Three years later, there are still movements to get developers to transition to a purely-PHP5 model.

Some of this may have transferred over to JavaScript, a language that is already poorly understood and often implemented even worse. It is often hard to find well-written, maintainable JavaScript code, as it is often left as an afterthought in a project or otherwise not given much consideration, having been delegated to the realm of popup scripts and mouse-overs. While exception handling may be overkill for a lot of JavaScript applications, many do not even know of JavaScript’s exception-handling capabilities. In this article, I’ll give a brief overview of exception handling and some recommendations on how to use it in JavaScript to improve the readability of code.

Exceptional conditions

I won’t go too in-depth about the merits of using exception handling but will instead just give a brief overview. (While there are some drawbacks, these apply more to the Java language rather than JavaScript)

The main reason for using exceptions is to have a separate channel for communicating errors. Without this, you must communicate error conditions using the function itself. Consider a function that performs mathematical division:

function divide(dividend, divisor)
{
  var quotient = dividend/divisor;
  return quotient;
}

Division is a fairly simple arithmetic operation, but of the four basic operations it is the only one that has limits on its arguments: the divisor (the term you divide by) cannot be zero, since division by zero is undefined. So, how should you handle cases where the supplied arguments result in division by zero? (The situation is very likely in an application accepting user input)

Without using exceptions, you have a few options, each of which has its own weaknesses. Firstly, you could choose not to return anything and just alert() the user of the error. This isn’t good since when you call the divide() function, you expect a result, not a warning message.

Secondly, you could choose to return a special “error code” indicating that there was a division by zero. But this creates another problem – what exactly do you return when something goes wrong? In this case, the only error case is division by zero – since JavaScript is a weakly-typed language, you could just return false on this error, but then in the calling code you’d have to check if divide() equaled false before using it, probably using the strict equality operator. As you can see, things get messy fast.

Alternatively, you could just check the inputs/arguments every time before you called the function. However this is clumsy, and adds another layer of complexity where something could go wrong.

Another way of doing things

As mentioned before, exception handling adds a side channel of sorts strictly for communicating errors. By doing this, it allows for the interruption of program flow for the purpose of dealing with the exception or error situation. Using exceptions, you would re-write the function above like this:

function divide(dividend, divisor)
{
  if (0 == divisor) {
    throw new Error("Bzlorg! Cannot divide by zero.");
  }
  
  var quotient = dividend/divisor;
  return quotient;
}

Here we are checking if the divisor equals zero – signifying an invalid input value – and then throwing an exception if this is the case. How is this different than returning an error code?

The main difference is in the control flow of the program; using exceptions causes a change in the program flow. In the above example, if the divisor equals zero, the execution of the function stops there and returns to the calling code with the throw exception. The subsequent statements calculating the quotient and returning will not be executed. Here’s an example of how you’d call the divide function.

try {
  var dividend = 3;
  var divisor = 0;
  
  var quotient = divide(dividend, divisor);

  alert("The answer is " + quotient);
}
catch (e) {
  alert(e.message);
}

With exceptions, you enclose code that could throw an exception with a try block. This signifies to the interpreter (in the case of JavaScript) that you will be executing code (in this case, calling a function) that could throw an exception as a result of some error condition. Thus you are trying to do something – but as in real life, things may go wrong.

In this example, everything works until the line calling divide. Since divide throws an exception with the input values supplied, flow will be directed to the catch block. All try blocks must be followed with a catch block, with the variable in the parentheses specifying the variable to hold the thrown exception object. In the code above, we merely alert the user to the problem – the message “Bzlorg! Cannot divide by zero” is displayed – in a real program you most likely would want to do handle the error differently depending on the context – but that’s a whole different topic.

If, however, you executed the code with valid values and no exceptions were thrown, once the program had got to the end of the try block it would jump over the following catch block and the user would be alerted with the correct answer. Code within a catch block is only executed in the event that an exception is thrown.

Differences with Java

Since Java is an extremely popular language and one that also uses a similar exception handling model, it would be prudent to discuss some of the differences and similarities with it and JavaScript.

  1. No multiple catch blocks with JavaScript

    This is perhaps the biggest difference. If you’re familiar with Java you’ll know that different exception objects can be thrown during execution (all subclasses of the root/parent Exception class defined by Java), each signifying different error conditions. You catch each of them separately by using separate catch blocks, each specifying a particular class or parent class. However, with JavaScript, as you might have noticed from the code above, there can only be one catch block and thus there’s no need to specify the exception class.

    If, however, you want the granularity of working with different exception classes, you’ll have to use the instanceof operator within a catch block, like this:

    try {
      ...
    }
    catch (e) {
      if (e instanceof RangeError) {
        ...
      }
      else if (e instanceof TypeError) {
        ...
       }
    }

    It’s not as elegant as having multiple catch blocks, but it’s one way to deal with multiple exception types.

    Correction:

    It appears I was mistaken. In JavaScript, you can indeed have multiple catch blocks, as seen in the Core JavaScript 1.5 Guide from the Mozilla Developer Center. My initial example above is still valid syntactically, but this way may be more appealing. An example is as follows:

    try {
      ...
    }
    catch (e if e instanceof RangeError) {
      ...
    }
    catch (e if e instanceof TypeError) {
      ...
    }
    catch (e) {
      // General catch-all block.
      ...
    }

    It just goes to show that when you think you know something, you probably don’t! This is part of why I like JavaScript (and by extension, programming); there’s always more to learn and experience to be gained.

  2. Exception types

    The discussion of exception types brings us to another point – the different exception types in JavaScript. JavaScript defines some built-in exception types, all based off the parent Error object. These should suffice for most situations where you’re checking user input (the most common use), but if you’re developing a complex application you may want to define your own.

    In that situation, things get a little tricky, especially if you’re coming from Java. Despite the outward similarity, JavaScript does not uses classes like Java, but instead uses a prototype-based approach where inheritance comes from existing objects. In this respect, things can get complicated as there are debates on what the best way to inherit from objects is and to that degree, a few JavaScript libraries have been written to facilitate the extending of objects in JavaScript. These points are beyond the scope of this article, but I thought I’d just point you in the right direction.

    Interestingly, you can also throw many different types of expressions, and are not limited to the built-in exception types. For example, throw false; and throw "Hello World"; are valid statements, but in my opinion, it doesn’t make much sense to throw any type of expression just because you can. Using the built-in exception types (or defining your own) is a better practice, though throwing just String expressions might be alright in some situations.

  3. Runtime errors

    During execution, you code may trigger runtime errors within JavaScript – for example, when trying to reference a property on a non-existent object. These will also result in a new Error object being thrown, even though you did not define this throw in your code. If this happens within a try block, the exception will subsequently be caught in the following catch block, and if you’re not expecting this error you may miss it. (If, for example, you’re only looking for specific exception object types)

    This can create problems with some of the JavaScript debuggers out there like Firebug. Since the runtime exception is being caught, Firebug will not be able to catch it (it is prevented from “filtering” up), so you may not be able to locate the source of your error if you’re relying on the debugger.

    My recommendation is thus to ensure your code runs properly under normal conditions. Only then should you start using exceptions and try-catch statements. This will ensure that no unexpected runtime exceptions get caught. (The runtime errors are analogous to the unchecked runtime exceptions of Java in that they are not normally caught)

Summing it up

The whole point of using exceptions is not to make your code “work” better – anything that can be accomplished with exceptions can most likely be done without it, with just the same end result. The point is to make your code more readable, manageable and flexible. By using exceptions you get rid of having to use cumbersome “error codes”, the values of which you may forget later. You also get more flexibility with how you handle errors. You need not handle the error right in the function where it occurs – you can throw an exception to the calling code and handle the error there – or, alternatively, you could let the exception bubble up to a higher-level and handle all errors there. It really depends on your needs, but using exceptions allows for this to be implemented more readily.

Though exceptions may seem like overkill for JavaScript and despite the limitations of its exception handling model as compared to that of Java’s, there are still some benefits to using exceptions, especially for complex JavaScript applications that you may implement to improve the interactivity of your site.

Changes/Fixes

  • 2007-12-06: Changed throw new Exception(...) to correct statement of throw new Error(...).
  • 2008-01-08: Fixed incorrect assertion of “No Multiple Catch Blocks” in JavaScript; added remarks about being able to throw any type of expression.

4 Comments »

  1. I’m trying to figure out if you can handle exceptions across files? For example:
    File 1:
    function Throw()
    {
    throw new Error();
    }

    File 2: (imports from file 1)
    function TryCatch()
    {
    try
    {
    Throw();
    }
    catch(ex)
    {
    return ex.message;
    }
    }

    Can’t seem to get this to work. Complains that there is not try/catch block in Throw(). Is there a way around this?

    Thank,
    Paul

  2. Hi Paul,

    I wasn’t able to reproduce your error. How are you doing the import? I just linked the files using the <script> tags.

  3. Thanks for the article! ๐Ÿ™‚

  4. Hello Guys,
    A runtime error which causes to break the execution of a program is known as exception and mechanism to handle this exception so that program did not terminate abnormally is known as Exception handling……. for more details check out the following link….
    http://mindstick.com/Articles/ba0d0b0e-c5a2-40a6-8c27-0aba348bd2e4/?Exception%20handling%20in%20Java%20Script

    Thanks !!!

Comments are now closed for this entry.