Debug it! In this article we will take a look on testing the code and error handling in JavaScript.
Handling errors in JavaScript
At the beginning would have to say a few words about the need for testing.
We need to test everything! Preferably at each stage of creating the code. And we must take care of the quality of our code!
A good code is not only tested, but also the one that responds to unpredictable situations. This is known as exception handling, and this technique is also available in JavaScript.
Basic error handling in JavaScript
To start with a simple example: using onerror. Let’s suppose that the browser wants to load an image from a file that does not exist.
Example — define reaction for a specific problem (commented purposely):
<!-- <img src="not_existing_foobar.png" onerror="alert('An error occured')" /> -->
In this case we will get an alert with information, when loading of the image will be impossible.
Let’s consider another example below. It’s quite useful — tells us about what went wrong in our code when an error occurs.
Example — capture any fault, such as a nonexistent function:
window.onerror = function(sMsg, sUrl, sLine) { alert("Error:\n" + sMsg + "\nURL: " + sUrl + "\n Line: " + sLine); return true; } // call nonexistent function: nonExistentFunction();
The Error object
Error handling in JavaScript gives us different tools. One of them is the creation and throwing objects created for this purpose (Error object). Such object stores a more detailed error information.
Example — creating an object of Error type, to handle exception:
function divide(iNum1, iNum2) { if (arguments.length != 2) { throw new Error("divide() requires two arguments"); } else if (typeof iNum1 != "number" || typeof iNum2 != "number") { throw new Error("divide() requires two numeric arguments"); } /* else if (iNum2.valueOf() == 0) { throw new Error("Don't divide by zero"); } */ return iNum1.valueOf() / iNum2.valueOf(); } alert(divide("a")); // alert(divide(2, 0)); // alert(divide("a", 0));
A more detailed description of the object Error available on Mozilla Developer Center.
The try… catch… finally construction
The design of this type is found in many object-oriented languages and is used to handle exceptions.
In try block we put the code, which may work in an unpredictable way.
In catch block we put the code to catch and handle an exception.
And in optional finally block — code that executes independently, always after processing try / catch blocks.
Example — basic use of try / catch to handle exception:
try { window.nonExistentFunction(); alert("Method executed."); } catch (oException) { alert("An exception occurred: " + oException.message); } finally { alert("The end of try… catch…"); }
Even creating nesting is possible.
Example — nesting try / catch:
try { eval("a ++ b"); // instruction causes an error } catch (oException) { alert("An exception occurred."); try { // instruction causes an error var aErrors = new Array(10000000000000000000000); push(exception); } catch (oException2) { alert("Yet another exception occurred."); } } finally { alert("The end"); }
Here is an example even more associated with OOP. Let’s take a look closer on objects of the Error type.
In the code we define a type of error object (thrown in the exception), i.e. his instance. We do this in order to take action appropriate for the type of an error.
Example — error type test:
try { foo.bar(); } catch (e) { if (e instanceof EvalError) { alert(e.name + ": " + e.message); else if (e instanceof RangeError) { e.name + ": " + e.message); } // … etc }
As it’s JavaScript, this is quite elegant way.
There is another thing important for exception handling — throw statement.
The throw statement causes an exception. As the argument we o define the expression containing the value to use (throw).
Examples — throw:
throw "Error2"; throw 47; throw true; throw { toString: function() { return "I'm an object"; } };
Asserts in JavaScript
Asserts are structures placed in the code, through which the programmer assumes the truth of the expression, which is useful in checking the software for vulnerabilities and fault tolerance. In JavaScript, we can simulate the usage of assertions.
This example uses the assert() function to throw own JavaScript errors:
function assert(bCondition, sErrorMessage) { if (!bCondition) { throw new Error(sErrorMessage); } } function divide(iNum1, iNum2) { assert(arguments.length == 2, "divide() requires two arguments"); assert(typeof iNum1 == "number" && typeof iNum2 == "number", "divide() requires two numeric arguments"); // … handle other cases … return iNum1.valueOf() / iNum2.valueOf(); } alert(divide("a"));
The console, debuggers and profilers
Finally a word about the console, in purpose of code testing (in browsers supporting such a solution).
Example:
var ss = "Test"; console.log(ss);
Usually (unless they are specific reasons for doing so) be sure to turn off such instructions from the production code.
Most of us are familiar with, and probably often uses a brilliant tool: Firebug. I remember when the code has been developed without the use of this tool… And it’s hard to believe.
Firebug is associated with Firefox, but other browsers also provide similar solutions for programmers. They are invaluable when looking for causes of problems in JavaScript, HTML and CSS.
Firebug:
Development tools in Google Chrome:
In Safari:
Opera browser:
And even in IE:
Such tools are very useful in cross-browser tests.
Summary
I hope this small article will help someone with writing better and better code. And most of all, will allow to look more broadly at JavaScript error handling.
For some time, we will describe more tools useful for Web Developers, such as EcmaUnit, Selenium, JSLint, and others.
Thank you, and… no bugs!