Error Handling

Contact Us or call 1-877-932-8228
Error Handling

Error Handling

No matter how careful you are, it always seems that errors find their way into your code. Sometimes they are runtime errors caused by unpredicted scenarios. Sometimes the errors are just incorrect behavior of your code, popularly known as bugs.

Fortunately, we have tools to deal with either type of problem. In this lesson we will talk about detecting and handling errors, debugging and fixing bugs in our applications.

Runtime Errors

Web browsers are such a hostile environment that it is almost guaranteed that we will constantly deal with runtime errors. Users provide invalid input in ways you didn't think of. New browser versions change their behavior. Ajax calls can fail for any number of reasons.

Many times we cannot prevent runtime errors from happening, but at least we can deal with them in a manner that makes the user experience less traumatic.

Unhandled Errors

Look at this seemingly trivial code sample:

Code Sample:

AdvancedTechniques/Demos/simple-bug.html
---- C O D E   O M I T T E D ----

function getInput() {
	var name = prompt('Type your name');
	alert('Your name has ' + name.length + ' letters.');
}
getInput();
---- C O D E   O M I T T E D ----

It may not be obvious, but this code has a bug waiting to break free. If the user clicks Cancel or presses Esc the prompt() function will return null, which will cause the next line to fail with a null reference error.

If you as a programmer don't take any steps to deal with this error, it will simply be delivered directly to the end user, in the form of an utterly useless browser error message like the one below: Error dialog

Depending on the user's browser or settings, the error message may be suppressed and only an inconspicuous icon shows up in the status bar: Error icon This can be worse than the error message, leaving users thinking the application is unresponsive.

Globally Handled Errors

The window object has an event called onerror that is invoked whenever there's an unhandled error on the page.

Code Sample:

AdvancedTechniques/Demos/simple-bug-onerror.html
---- C O D E   O M I T T E D ----

window.onerror = function (message, url, lineNo) {
	alert(
		'Error: ' + message + 
		'\n Url: ' + url + 
		'\n Line Number: ' + lineNo);
	return true;			
}

function getInput() {
	var name = prompt('Type your name');
	alert('Your name has ' + name.length + ' letters.');
}
getInput();
---- C O D E   O M I T T E D ----

As you can see, the event will pass three arguments to the invoked function. The first one is the actual error message. The second one is the URL of the file containing the error (useful if the error is in an external .js file.) The last argument is the line number in that file where the error happened.

Returning true tells the browser that you have taken care of the problem. If you return false instead, the browser will proceed to treat the error as unhandled, showing the error message and the status bar icon.

Here's the message box that we will be showing to the user: Error message

Structured Error Handling

The best way to deal with errors is to detect them as close as possible to where they occur. This will increase the chance that we know what to do with the error. To that effect JavaScript implements structured error handling, via the try...catch...finally block, which is also present in many other languages:

try {
	//try statements
} catch (error) {
	//catch statements
} finally {
	//finally statements
}

The idea is simple. If anything goes wrong in the statements that are inside the try block, then the statements in the catch block will be executed and the error will be passed into the error variable. The finally block is optional and, if present, is always executed last, whether or not an error is caught.

Let's fix our example to catch that error:

Code Sample:

AdvancedTechniques/Demos/simple-bug-try-catch.html
---- C O D E   O M I T T E D ----

window.onerror = function (message, url, lineNo) {
	alert(
		'Error: ' + message + 
		'\n Url: ' + url + 
		'\n Line Number: ' + lineNo);
	return true;			
}

function getInput() {
	try {
		var name = window.prompt('Type your name');
		alert('Your name has ' + name.length + ' letters.');			
	} catch (error) {
		alert('The error was: ' + error.name + 
		'\n The error message was: ' + error.message);
	} finally {
		//do cleanup
	}
}
getInput();
---- C O D E   O M I T T E D ----

The error object has two important properties: name and message. The message property contains the same error message that we have seen before. The name property contains the kind of error that happened and we can use that to decide if we know what to do with that error.

With that in place, if we reload the page and cancel out of the prompt, we will get the following alert: Error message

It's good programming practice to only handle the error on the spot if you are certain of what it is and if you actually have a way to take care of it (other than just suppressing it altogether.) To better target our error handling code, we will change it to only handle errors named "TypeError", which is the error name that we have identified for this bug.

Code Sample:

AdvancedTechniques/Demos/simple-bug-try-catch-specific.html
---- C O D E   O M I T T E D ----

window.onerror = function (message, url, lineNo) {
	alert(
		'Error: ' + message + 
		'\n Url: ' + url + 
		'\n Line Number: ' + lineNo);
	return true;			
}

function getInput() {
	try {
		var name = window.prompt('Type your name');
		alert('Your name has ' + name.length + ' letters.');			
	} catch (error) {
		if (error.name == 'TypeError') {
			alert('Please try again.');
			getInput();
		} else	{
			throw error;
		}
	} finally {
		//do cleanup
	}
}
getInput();
---- C O D E   O M I T T E D ----

Now if a different error happens, which is admittedly unlikely in this simple example, that error will not be handled. The throw statement will forward the error as if we never had this try...catch...finally block. It is said that the error will bubble up.

Throwing Custom Errors

We can use the throw statement to throw our own types of errors. The only recommendation is that our error object also has a name and message properties to be consistent with the built-in error handling.

throw {
	name: 'InvalidColorError', 
	message: 'The given color is not a valid color value.'
};
Next