Friday, April 4, 2014

Microsoft 70-480: Implement exception handling

Exam Objectives


Set and respond to error codes; throw an exception; request for null checks; implement try-catch-finally blocks


Quick Overview of Training Materials


Programming in HTML5 with JavaScript and CSS3 - Training Guide - Chapter 3
Advanced Windows Store App Development with HTML5 Jump Start - Module 6
How to check for undefined or null variable in javascript - Stackoverflow
JavaScript null check - Stackoverflow
MSDN - Error Object (JavaScript)
JavaScript spec
When JavaScript Feature Detection Fails


The Error object and error types


In JavaScript, any time an error is encountered, an Error object is created and thrown. The generic error object has a message and a name property, while the Microsoft implementation adds a number and description, and the Mozilla implementation adds filename, linenumber, columnnumber, and stack properties. There are a number of specific error types as well:
  • EvalError - an error that occurs in eval().
  • RangeError - occurs when a parameter passed to a function is outside the allowable range.
  • ReferenceError - generally occurs when you try to reference an object that hasn't been created yet
  • SyntaxError - occurs when the interpretter encounters incorrect code, e.g. missing semicolons or parens, keywords in the wrong place, that sort of thing...
  • TypeError - thrown when a parameter is not the right type. Passing circular objects to JSON.stringify for example, or trying to execute with () an object that isn't a function.
  • URIError - using encodeURI() and decodeURI() the wrong way. One example is passing a surrogate character code that isn't part of a high-low pair (see below)
A few of the errors I encountered writting prior blog posts:


In the interest of completness, I wanted to see if I could throw the other types as well. I couldn't get an EvalError to throw, and then I looked in the spec and found out it is not really used but is instead just a backward compatibility relic:



While I was playing around I stumbled across a couple interestnig non-errors. Math functions are pretty forgiving, if you screw something up you might get NaN but it won't throw an error. The encodeURI() and decodeURI() functions will take pretty much anything for an argument and use it anyway:


Set and respond to error codes, throw errors


In the specification, the only parameter passed to the error constructor is message. This becomes the message property on the newly defined Error object.  Because the Error object is still an object, it is possible to define other properties on the object just by assigning them. So if you want to use a number or errorCode property, it is easily done by assigning values to them. These can then be used in the catch block for whatever purpose they were intended. As demonstrated here, you can throw an error manually just by calling using the throw keyword:

try {
   err = new Error("I'm an error");
   err.errCode = 9999;
   throw err;
}
catch(e)
{
   switch(e.errCode){
   // case for each errCode
   }
}

Null checks, truthy and falsey values


Sometimes we need to know if something exists and, if so, if it's null.  This is probably a good time to go over truthiness and falsiness, as well as revisit logical operator short circuiting as well, since both are relevant to the discussion of null checking.    

First off, when using condition checks, literal true and false boolean values are not the only values that effectively evaluate to true or false.  Null, undefined, 0, "" (empty string) all evaluate to false.  So if we want to check if a variable has a property, we can use the following code:

if(obj.someprop)
{
   // do something if the property exists
}
else
{
   // do something else if the property doesn't exist
}

It should be noted that this test will not work if obj has not yet been declared.  Trying to test an undeclared variable in this way will result in a runtime error (ReferenceError, as a matter of fact). To test if a variable has been declared or not, use typeof x == "undefined" where 'x' is the variable name we are testing.

The sitepoint article points out that some feature detection is a little trickier than this.  One classic example is testing for ActiveX in Internet Explorer. Because of late binding, it is impossible to know if ActiveX is available until you try to use it, and if you try and it is disabled, you will throw an exception.  So testing for ActiveX requires the use of a try...catch block (discussed below).  Another problem is testing for DOM properties in some browsers (cough... IE... cough). If we want to test if an HTML5 API is available (they use draggable as an example), the most reliable way to test is to create a new element and test that:

if( "property" in document.createElement("whatever") ) {}

One last thing about null checks. Inside a function, the parameters are automatically declared, so you never have to use the typeof check on a parameter within the function. If an undefined value (like a non-existant object property or even the literal 'undefined' value) is passed to the function, if(param) will evaluate to false, it will NOT throw an error. Here are some truthiness and falsiness tests:


try... catch... finally


If you have a section of code that may throw an exception, and you want to change the behavior of your code based on whether this exception is thrown, you'll need to use a try-catch block.  The code that may throw an exception is placed in try{}, and the code to handle any exceptions is placed in catch(e){}, where e is the exception object:


While Mozilla supports conditional catch blocks, it is quite simple to do condition testing in a single catch block and treat the error differently based on what kind of error it is:



No comments:

Post a Comment