Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Exceptional JavaScript

DZone's Guide to

Exceptional JavaScript

· Web Dev Zone
Free Resource

Should you build your own web experimentation solution? Download this whitepaper by Optimizely to find out.

JavaScript is becoming a complex environment, and often not only presentation logic but also business one is moved to it for a faster response to the end user (without having data gone for a round trip on the server in order to be validated.) In some cases, JavaScript is even used on the server side, such as in CouchDb views, or in the Persevere object store.

Thus, we should start treating JavaScript like a real programming language: it has an object model (more than a single one actually), can support modular programming and related libraries are growing in number and size.

I recently saw an introduction to JavaScript by Misko Hevery, Agile Coach at Google. He did a great job of presenting the JavaScript programming paradigm with its asynchronous callbacks and assignments that cause side effects. But if there is one thing to learn about JavaScript, is that JavaScript is a full-fledged language, widely supported across browser without major differences: this language supports functional programming, and various form of object-oriented one. The problems that arise on compatibility are due to the set of APIs exposed by the browser, which has never become a standard and makes a pain working without a framework that deal with the browsers peculiarities.

Error handling

When you get to a certain application size, you may want to introduce some serious error handling, particularly in JavaScript-intensive web applications. When Facebook or GMail scripts fail, usually they do not hang without doing anything (unlike the most of our web app), but they signal the error in a small fake-popup script.

Graceful degradation when errors are encountered is a desiderable feature. Ajax techniques will only make the interactions with the server increase in number and the probability of encountering at least one failure will grow accordingly.

Thus, we should look for a mechanism for simplifying error handling. Exceptions are the most diffused infrastructure for error handling nowadays, in server-side languages like PHP and Java, so why don't employ them also in JavaScript? Exceptions are a powerful alternative no return codes, and they can skip various levels of functions to bubble up just where you want to catch them and handle the failure, without the intermediate code noticing. And they have been supported in JavaScript for several years.

General syntax and samples

This article will be code-intensive, since the best way to learn a programming language is experimenting with it. I encourage you to follow along and try these snippets in your browser, tweak them and edit them until they stop working.

I guess if you are reading this post you are already a bit familiar with exceptions and how they are used in other languages. Basically, in case of error you throw something, and it climb over the stack by make every function return immediately, breaking the normal flow of execution:

<script type="text/javascript">
function divisionCanFail(a, b) {
if (b == 0) {
throw "Division by zero.";
}
return a / b;
}
alert(divisionCanFail(5, 0));
</script>

If you load this small HTML page in your browser (Firefox with FireBug or Chrome), you will notice an error displayed in your console.

Unlike in other languages, where exceptions must be subclasses of a common Exception class, in JavaScript we can throw anything from strings to numbers and objects. Of course, objects can contain much more information.

How do we catch an exception before it reaches the outermost level and gets show up in the console? We can handle it differently instead.

<script type="text/javascript">
function divisionCanFail(a, b) {
if (b == 0) {
throw "Division by zero.";
}
return a / b;
}
try {
alert(divisionCanFail(5, 0));
} catch (error) {
alert("Error: " + error);
}
</script>

The exception has been catched. Of course, you would wonder if the finally keyword is also supported, to define cleanup code that always get executed even if an exception is raised. It is:

<script type="text/javascript">
function divisionCanFail(a, b) {
if (b == 0) {
throw "Division by zero.";
}
return a / b;
}
try {
alert(divisionCanFail(5, 0));
} catch (error) {
alert("Error: " + error);
} finally {
alert("Here we should clear up.");
}
</script>

We have said that JavaScript does not require you to extend an Exception basic class, but it has one. It is named Error and its instances contain some useful informations on where the exception has occurred:

<script type="text/javascript">
function divisionCanFail(a, b) {
if (b == 0) {
throw new Error("Division by zero.");
}
return a / b;
}
try {
alert(divisionCanFail(5, 0));
} catch (error) {
alert("Error: " + error.message);
alert(error.fileName + " at " + error.lineNumber);
alert(error.stack);
}
</script>

 This class has several subclasses, which the interpreter uses when it finds common errors. For example, ReferenceError is raised whenever a not existent property or item is accessed:

<script type="text/javascript">
try {
notExistentArray[2] = "value";
} catch (error) {
alert("Error: " + error.message);
alert("Exception class: " + error.name);
}
</script>

This will show Exception class: ReferenceError. There are other subclasses: EvalError, RangeError, SyntaxError, TypeError, and URIError. You can throw them in your code as the JavaScript interpreter does.

Using the conventional name field for error objects, we can also introduce multiple catch blocks, one for every kind of exception we want to stop from bubbling up:

<script type="text/javascript">
function DivisionByZeroError() {
this.name = "DivisionByZeroError";
}
function DivisionByStringError() {
this.name = "DivisionByStringError";
}

function divisionCanFail(a, b) {
if (b == 0) {
throw new DivisionByZeroError();
}
if (typeof b == "string") {
throw new DivisionByStringError();
}
return a / b;
}

function decoratedDivision(a, b) {
try {
alert(divisionCanFail(a, b));
} catch (error if (error.name == "DivisionByZeroError")) {
alert("A division by zero...");
alert("Exception class: " + error.name);
} catch (error if (error.name == "DivisionByStringError")) {
alert("Exception class: " + error.name);
}
}

decoratedDivision(5, "isThisANumber?!");
decoratedDivision(5, 0);
</script>

All the code in this article has been tested with Firefox 3.x and Firebug.

Implementing an Experimentation Solution: Choosing whether to build or buy?

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}