As programming languages like VBScript and JavaScript have become more complex and sophisticated, so too have the errors that programmers make when writing code. With error handling, however, you can write code into your script that traps errors and solves them internally or alerts the end user to the error with an informative message. For example, if a script calls an ActiveX control or Java applet that is not fully loaded, it would normally result in an error dialog being displayed to the user. This can be circumvented with error-handling code.
Handling the onerror event is one way to trap and work around scripting code errors. When an error occurs in a specified object, an onerror event is fired and the user is alerted. Objects that support onerror include the IMG, LINK, OBJECT, SCRIPT, STYLE, and, most useful of all, window objects. Netscape Navigator versions 3 and later and Internet Explorer versions 4 and later support onerror. Code Listing 10-2 shows a basic use of the onerror event. Figures 10-2 and 10-3 display the results.
Code Listing 10-2.
<HTML> <HEAD> <TITLE>Listing 10-2</TITLE> <SCRIPT LANGUAGE="JavaScript"> function jHandleImageError(oImg){ alert(`Could not load the image `+oImg.name+". Loading alternate.") oImg.src=`unavailable.gif' } </SCRIPT> </HEAD> <BODY> This image does not use an error handler. <IMG SRC="one.gif" NAME="ImageOne"><BR> This image does use an error handler. <IMG SRC="two.gif" NAME="ImageTwo" onerror="jHandleImageError(this)"> </BODY> </HTML> |
Figure 10-2. A programmed error message appears...
Figure 10-3. ...and then an alternate image is loaded.
When Code Listing 10-2 is run, it first attempts to load the images one.gif and two.gif, which can't be found, because neither image is included on the companion CD. The ImageOne object cannot load the one.gif graphic and fires the onerror event. No action is taken because there is no error handler on this image, so the user is left with only a missing graphic symbol. When the browser tries to load two.gif, the onerror event fires again. This time an in-line onerror event handler captures the error. The event handler calls a function that alerts the user with an error message and then loads an alternate graphic. The in-line event handler can also be used on OBJECT and SCRIPT elements to point to alternate resources when the browser is unable to load a file.
In the window object, onerror works to trap general errors. Code Listing 10-3 shows what happens when a page of script without error handling calls an object that does not exist.
Code Listing 10-3.
<HTML> <HEAD> <TITLE>Listing 10-3</TITLE> </HEAD> <BODY> Clicking this button calls a nonexistent object. <FORM><INPUT TYPE="button" VALUE="Click Me" onclick="FakeO.use()"></FORM> </BODY> </HTML> |
Figure 10-4. The error dialog from Internet Explorer when Code Listing 10-3 is run.
When the user clicks the button, its onclick event handler attempts to use a method from an object that doesn't exist. This results in a standard undefined object error message being presented to the user, shown in Figure 10-4. The next code listing traps the error. The results are shown in Figure 10-5.
Code Listing 10-4.
<HTML> <HEAD> <TITLE>Listing 10-4</TITLE> <SCRIPT LANGUAGE="JavaScript"> function errorHandler(msg,url,line) { strPrompt=("Captured error \n"+msg+"\n on line "+line+" in "+url+".") strPrompt+=("\nCancel display of standard error message?") if (confirm(strPrompt)){return true} else {return false} } window.onerror=errorHandler; </SCRIPT> </HEAD> <BODY> Clicking this button calls a non-existent object. <FORM><INPUT TYPE="button" VALUE="Click Me" onclick="FakeO.use()"></FORM> </BODY> </HTML> |
Figure 10-5. Code Listing 10-4 handles the error.
When Code Listing 10-4 is first loaded, an errorHandler function is added to the window object with the statement window.onerror=errorHandler. This statement means that whenever the window object fires the onerror event, the errorHandler function will be called. The errorHandler function takes three parameters that contain information about the error. The msg parameter contains the text of the error message, url provides the URL of the page in which the error occurred, and line provides the line number of the script that caused the error. These parameters are available only from an onerror event handler on the window object, not on other objects, such as images. Using these parameters, the function then formats and presents an error message to the user, along with the option to cancel the default error message. If the errorHandler function returns the value true, the window object will not display an additional error message. If false or no value is returned, the regular error message will be displayed. The errorHandler function can also prevent any error message from being displayed with a return true statement, or by setting the window.event.returnValue property to true.
In addition to the in-line onerror event handler demonstrated in Code Listing 10-2 and the window.onerror handler shown in Code Listing 10-4, you can create a specific script block containing the error-handling code, as follows:
<SCRIPT LANGUAGE="JavaScript" FOR="window" EVENT="onerror(msg,url,line)"> [...script commands...] </SCRIPT> |
This type of script block works only in Internet Explorer, not in current versions of Netscape Navigator.
A new mechanism for error handling that is currently supported in the JScript 5 script engine, which comes with Internet Explorer 5 and can be used in IIS and earlier versions of Internet Explorer, is the try...catch statement. It is very useful when running script on the server, where there is no window object. It is also handy because different error-handling code can be placed around different problem areas. Code Listing 10-5 shows a try...catch statement. Figure 10-6 displays the results.
Code Listing 10-5.
<HTML> <HEAD> <TITLE>Listing 10-5</TITLE> <SCRIPT LANGUAGE="JavaScript"> try { document.write("This statement works.") document.write(fakeO.use()) document.write("This statement does not work.") } catch (e) { strError=("An error occurred. The error number was "+e.number+". ") strError+=("The error message was \""+e.description+"\"") alert(strError) } </SCRIPT> </HEAD> <BODY> </BODY> </HTML> |
Figure 10-6. Code Listing 10-5 handles an error with a try...catch statement.
As the page is being loaded, the script block is run. As you can see, the script begins with a try block, which contains a series of statements that the browser attempts to run. If any of the statements results in an error, the error is trapped and passed to the subsequent catch block, which constructs and displays an error message.
The first statement in the try block is a document.write method that has no errors and is executed successfully. The second line calls on an object and a method that do not exist. This causes an error, and so the catch block is called, which constructs and then displays an error message.
The catch statement is automatically passed a parameter that contains an error object. This object has two properties, number and description. Each type of script error is assigned a unique error number. The number property can be tested and can cause different effects depending on the error. The description property contains a textual description of the error.
The try...catch statement is especially useful on the server side, where there is no window object to trap errors. It can also be used to set default values. For example, the following statement will assign the value of b to a, unless there are any problems doing so (for instance, if b doesn't exist), in which case a will be assigned the value 5 instead.
try {a=b} catch {a=5} |
The throw statement can be used to pass a specific error message to a catch statement. It can also be used to pass an error to a higher-level error handler in the case of nested try...catch statements. Code Listing 10-6 demonstrates both of these techniques.
Code Listing 10-6.
<HTML> <HEAD> <TITLE>Listing 10-6</TITLE> <SCRIPT LANGUAGE="JavaScript"> processedSuccessfully=false sProb="" while (!processedSuccessfully){ try { try { intInput=prompt(sProb+"Enter a number to divide into 100.",4) // send specific error to inner handler if (isNaN(intInput)){throw "NaN"} if (intInput==0){throw "div0"} x=(100/intInput) sOutput=("100 divided by "+intInput+" equals "+x) processedSuccessfully=true } catch(e) { sErr="Handled in inner handler. " if (e == "NaN"){ sProb=(sErr+"You did not enter a valid number.\n") } // send other errors to outer handler else{throw e} } } catch(e) { sErr="Handled in outer handler. " if (e=="div0"){ sProb=(sErr+"You entered 0, which cannot be a divisor.\n") } else{sOutput=(sErr+e.description);break} } } document.write(sOutput) </SCRIPT> </HEAD> <BODY> </BODY> </HTML> |
Code Listing 10-6 begins by prompting the user for a number. The code uses a while loop that continues to prompt the user until a number is entered that meets the code's requirements, or until a break statement is called that takes the user out of the while loop. When a valid number is entered, the code divides the number into 100 and adds the result to the sOutput variable, which is then written to the browser window.
There are, however, several predictable user input errors that could upset this process. A user could, for instance, enter 0, which does not divide meaningfully into 100, or the user could enter text instead of a number. Additionally, some type of unexpected error could occur. As a result, we've utilized the try, catch, and throw statements in our code to test for, capture, and report these types of errors.
The inner try statement tests whether the user entered data that is not a number and whether the number entered is 0. If either of these situations occur, the throw statement is used to send information about the error to the catch statement, which creates and displays a specific error message. If any other errors occur, they are automatically sent to the catch statement, as usual.
If the user enters a non-number (text or symbol) string, the inner catch statement detects this error and adds it to the sProb variable, which is appended to the prompt when the user is next asked for a number. If the user enters 0, the error is thrown to the outer catch statement, which also modifies the sProb variable. Any other errors are described in the sOutput variable, after which the break statement is used to exit the while loop. The document.write method then describes these errors on the screen. To cause such a problem, copy the listing to your hard drive and comment out the line that reads x=(100/intInput). This will cause an `x' is undefined error message to display.
The JScript scripting engine inside Internet Explorer can return the errors shown in Table 10-1. This table does not list errors returned by objects that are external to the scripting engine (like the Media Player and other ActiveX controls) and that can return their own custom errors.
Table 10-1
Error Number | Error Description |
---|---|
5 | Invalid procedure call or argument |
6 | Overflow |
7 | Out of memory |
9 | Subscript out of range |
10 | This array is fixed or temporarily locked. |
11 | Division by zero |
13 | Type mismatch |
14 | Out of string space |
17 | Can't perform requested operation |
28 | Out of stack space |
35 | Sub or Function not defined |
48 | Error in loading DLL |
51 | Internal error |
52 | Bad file name or number |
53 | File not found |
54 | Bad file mode |
55 | File already open |
57 | Device I/O error |
58 | File already exists |
61 | Disk full |
62 | Input past end of file |
67 | Too many files |
68 | Device unavailable |
70 | Permission denied |
71 | Disk not ready |
74 | Can't rename with different drive |
75 | Path/File access error |
76 | Path not found |
91 | Object variable or With block variable not set |
92 | For loop not initialized |
93 | Invalid pattern string |
94 | Invalid use of Null |
322 | Can't create necessary temporary file |
424 | Object required |
429 | Automation server can't create object |
430 | Class doesn't support Automation |
432 | File name or class name not found during Automation operation |
438 | Object doesn't support property or method <item> |
440 | Automation error |
445 | Object doesn't support this action |
446 | Object doesn't support named arguments |
447 | Object doesn't support current locale setting |
448 | Named argument not found |
449 | Argument not optional |
450 | Wrong number of arguments or invalid property assignment |
451 | Object not a collection |
453 | Specified DLL function not found |
458 | Variable uses an Automation type not supported in JScript |
501 | Cannot assign to variable |
502 | Object not safe for scripting |
503 | Object not safe for initializing |
504 | Object not safe for creating |
5000 | Cannot assign to `this' |
5001 | <Item> is not a number; Number expected |
5002 | <Item> is not a function; Function expected |
5003 | Cannot assign to a function result |
5004 | <Item> is not an indexable object; Cannot index object |
5005 | <Item> is not a string; String expected |
5006 | <Item> is not a date object; Date object expected |
5007 | <Item> is not an object; Object expected |
5008 | Cannot assign to <item>; Illegal assignment |
5009 | <Item> is undefined; Undefined identifier |
5010 | <Item> is not a boolean; Boolean expected |
5011 | Can't execute code from a freed script |
5012 | Cannot delete <item>; Object member expected |
5013 | <Item> is not a VBArray; VBArray expected |
5014 | <Item> is not a JScript object; JScript object expected |
5015 | <Item> is not an enumerator object; Enumerator object expected |
5016 | <Item> is not a regular expression object; regular expression object expected |
5017 | Syntax error in regular expression |
5018 | Unexpected quantifier |
5019 | Expected `]' in regular expression |
5020 | Expected `)' in regular expression |
5021 | Invalid range in character set |
You will notice that the numbers reported in this table differ substantially from those reported by the actual number property. Code Listing 10-7 demonstrates how to convert the number reported in the number property to the one shown in the chart above. Figure 10-7 displays the results.
Code Listing 10-7.
<HTML> <HEAD> <TITLE>Listing 10-7</TITLE> <SCRIPT LANGUAGE="JavaScript"> try { x=y } catch (e) { strError=("An error occurred. error.number was "+e.number+"\n") strError+=("Convert this and get "+(e.number&0xFFFF)+"\n") strError+=("The error message was \""+e.description+"\"") alert(strError) } </SCRIPT> </HEAD> </HTML> |
Figure 10-7. Code Listing 10-7 converts an error to the value shown in Table 10-1.
The technical explanation for this is as follows. The numbers in Table 10-1 represent only the lower order bits of the number in e.number. The second line that references e.number performs a bitwise AND operation with the & operator to retrieve only the lower order bits. This is also known as performing a bit mask. You can find out more about the & operator at msdn.microsoft.com/scripting, where you can also find more information about handling errors.
So far, we've looked at some functions and features of HTML and scripting. Part 3 introduces Cascading Style Sheets (CSS), a technology that has been around since Internet Explorer 3 but that has been greatly expanded since then. CSS gives you extensive control over the appearance of your pages and makes it easy to give an entire Web site a consistent look and feel.