By Greg Ferrell » December 29, 2008

When using multiple JavaScript libraries, it is inevitable that one JavaScript file will need to call functions named in other libraries. This is necessary but can cause issues if all of the libraries aren't present.

Error handling with JavaScript is somewhat lackluster. With this in mind, you should do your best to catch and handle errors and avoid sending them to the end-user. In order to prevent errors and allow for scalability, you should test for functions that aren't present in the script where you are calling them.

Lets say for example that you have downloaded a JavaScript library named "bob.js" and it contains just a main function named "bob". To keep things clean, you might load this file separately. (Of course this is a bit unrealistic, no one would make a separate file for one function, but for the sake of example, bear with me.) Your loading code might look like this:

<script type="text/javascript" src="bob.js"></script>
<script type="text/javascript" src="mycode.js"></script>

So, correctly, we have loaded the "bob" library first and our code second.

For the sake of example and understanding, lets suppose that the "bob" function just returns a simple math result. It isn't important what the bob function does, but it might be easier for some to understand if we had a real example:

//bob.js
function bob(n)
{
	return n * n;
}

Now this takes us to our real example. Given that we have the function "bob" in another file, we want to use it in our own code, "mycode.js". When the page loads, we want to add a div tag with some text that has a number in it. We are going to use the "bob" function to return the number to the power of 2 and write it:

//mycode.js
window.onload = function()
{
	//the starting number
	var oldNum = 43;
	
	//make the number we are going to write
	var newNum = bob(oldNum);

	//set the body tag to a variable
	var body = document.getElementsByTagName('body')[0];
	
	//make the div container
	var myDiv = document.createElement('div');
	
	//create the text container
	var myText = document.createTextNode(newNum);
	
	//add the text to the div
	myDiv.appendChild(myText);
	
	//add the div to the body
	body.appendChild(myDiv);
}

While the above code could be written quite a bit smaller, it works well and it is plain what is happening. You run into an issue however when the "bob.js" file isnt present. When you run into an error in JavaScript, it usually kills the chain the function or event is called in. So in the above instance, as soon as it hit the second variable, and the bob code wasn't present, the code would simply halt on error and nothing would display on screen, potentially breaking many other things in the process.

This brings the issue of error handling and function testing. One of the tools that we do have in JavaScript is the try/catch(/finally) statement. It is very handy for areas of code that can be error prone or have outside influence on the application. We could fix our example by adding a try/catch statement that would have a backup variable in case the "bob.js" isn't present:

//mycode.js
window.onload = function()
{
	//the starting number
	var oldNum = 43;
	
	//make the number we are going to write
	try {	
		//works if bob is present
		var newNum = bob(oldNum);
	} catch(e) {
		//catches the error if bob is missing and provides an alternative
		var newNum = oldNum;
	}

	//..etc
}

This will effectively remove the chance for error if "bob.js" isn't present. However, the try/catch statement takes a bit of a performance hit due to all it is designed to do. When simply testing for functions, I feel it is a bit verbose.

My personal preference is just to test for the existence of the function before I attempt to call it. This way you don't spend the CPU time calling the function, getting the failure, sending the error, catching the error, then running the error block. When testing for a function, it's usually best to make sure it is actually a function rather than simply checking for it to be not undefined. This is doubly important in situations where you are using multiple libraries or working with a lot of people on the same file. Your code and their code could have the same name for two different types of objects. JavaScript has no overwrite protection even on its own built in functions unless specific platforms add it in, therefor you must take it upon yourself to check.

Checking for the existence of functions can be done easily using the typeof operator in JavaScript. Many times, I code that simply checks for "undefined" or not, then lets the code run. As mentioned above, this still leaves some potential for errors in your code. Granted, there will always be margin for error, but the goal is to make habits that minimize it and help you the real issues. Therefore I think it is better to make sure your function is actually a function. The same code we used with the try/catch statement can be written similarly with the typeof checking:

//mycode.js
window.onload = function()
{
	//the starting number
	var oldNum = 43;
	
	//make the number we are going to write
	if(typeof bob === "function") {	
		//works if bob is present and is a function
		var newNum = bob(oldNum);
	} else {
		//if bob is not present, provides an alternative
		var newNum = oldNum;
	}

	//..etc
}

This has better performance than the try/catch statement and gives you a better idea where an error could be if it occurs. However, we could write this even shorter to make the code a little cleaner using a ternary operator:

//mycode.js
window.onload = function()
{
	//the starting number
	var oldNum = 43;
	
	//make the number we are going to write
	//if bob is present and is a function, make number
	//if bob is not present, provides an alternative
	var newNum = (typeof bob === "function")? bob(oldNum) : oldNum;

	//..etc
}

One last thing to mention when using typeof. It will throw an error if you are testing for a function inside of a nonexistent parent. So, say "bob" is an object, with a subobject "math", with a method called "double". If we test for "bob.math.double" and "bob" doesn't exist, JavaScript will throw an error with the typeof operator. To avoid such errors you could test for each segment of the method's parent chain before testing for the method itself:

//mycode.js
window.onload = function()
{
	//the starting number
	var oldNum = 43;
	
	//make the number we are going to write
	if(typeof bob === "object" && 
	   typeof bob.math === "object" &&
	   typeof bob.math.double === "function") {	
		//works if bob is present and is a function
		var newNum = bob.math.double(oldNum);
	} else {
		//if bob is not present, provides an alternative
		var newNum = oldNum;
	}

	//..etc
}

This seems a lot longer given the possibilities of nested objects, but doing it this way also prevents the issue of same-named objects clobbering each other and sneaking in to create errors. If you are really confident with your code and have no outside workers/code coming in, you could skip the middle statements and just test for the parent object.

There we have it. This method of function existence checking has saved me lots of time and has created some interesting idioms for projects where external code may or may not be present. Enjoy!

blog comments powered by Disqus