reptile7's JavaScript blog
Saturday, October 31, 2009
 
Follow the Error
Blog Entry #161

In our last episode, we applied a basic error-handling function to the jserrorpage.html demo page of HTML Goodies' "The onerror Event Handler" tutorial: that function duly caught jserrorpage.html's document.wrte("dog") error and returned the error line number in the jserrorpage.html source. But let's set the bar a bit higher, shall we? What if we were dealing with a page/script that contains two, three, or even a whole bunch of errors?

Consider, for example, the assignment script for HTML Goodies' JavaScript Primers #2 ("Error Messages"):

...x
dothis = new Date( );
month = dothis.getMonth( );
month = (month * 1) + 1;
day = dothis.getDate( );
year = dothis.getFullYear( );
document.wrte(" ", month, "/", day, "/", year, " ");


There are two problematic lines in the above code: the first line will throw a syntax error whereas the last line contains a misspelled-method* run-time error. (Technically, there are three syntax errors and also a latent 'x is not defined' run-time error on the first line, but the syntax error associated with the first . period character is all that's necessary to bring the script to a halt.) My error-handling function only catches the initial syntax error, which is perhaps not so surprising given that the default error-handling mechanisms for the browsers on my computer also only report the syntax error.
(*"Object member expected" is Microsoft's current description for this type of error.)

A browser's HTML layout engine is designed to cope with invalid HTML (e.g., it will typically ignore unrecognized element tags and attributes), but its JavaScript engine is nowhere near as forgiving. I find that a syntax error will shut down an entire script, even if the error line
(a) is preceded by valid code, or
(b) appears in a to-be-called-later function and the script also contains valid top-level code.
Run-time errors are less controlling: a top-level run-time error will kill top-level code that follows it, but will not interfere with preceding top-level code nor with functionized code.

So, as long as the ...x and document.wrte(" ", month, "/", day, "/", year, " "); lines are in the same script, we're not going to see an error for the latter line. However, if we were to put these lines in separate scripts, then we'd see errors for both of them.

When it introduced the onerror event handler in JavaScript 1.1, Netscape also rolled out an "Example 3: Error handling function" that intercepts JavaScript errors, the implication being that the code thereof flags all** of the script errors, internal and external, associated with a document. In fact, and as might be expected from the foregoing discussion, Netscape's Example 3 will not flag ≥2 errors in a given script - at least it won't do so with Netscape 4.x and later Netscape/Mozilla browsers - but it does a better job of collecting and displaying error information than my error-handling function does, so I thought we would run through it.
(**"We never said all," Netscape might protest. Fair enough, but if you meant "some" and not "all", then you should have made that explicit in the example's description.)

Example 3 collects error information via the code below:
window.onerror = myOnError;

msgArray = new Array( );
urlArray = new Array( );
lnoArray = new Array( );

function myOnError(msg, url, lno) {
   msgArray[msgArray.length] = msg;
   urlArray[urlArray.length] = url;
   lnoArray[lnoArray.length] = lno;
   return true;
}
The beginning window.onerror = myOnError; statement coassociates the window object, error events, and the myOnError( ) error-handling function.

We next create three arrays for holding information about error events: msgArray, urlArray, and lnoArray. Initially these arrays are empty and their lengths are all 0.

The myOnError( ) function is triggered directly by error events and serves to populate the msgArray/urlArray/lnoArray arrays with information about those events:

• For each error detected by the JavaScript engine, the message, file URL, and line number of the error are sent to myOnError( ) and respectively assigned to myOnError( )'s arguments[0], arguments[1], and arguments[2] - msg, url, and lno in this case - as detailed in the previous entry.

• For a first error, myOnError( ) respectively assigns msg, url, and lno to msgArray[0], urlArray[0], and lnoArray[0]. These assignments effectively increment the length of each array to 1, so that for a second error, msg, url, and lno are assigned to msgArray[1], urlArray[1], and lnoArray[1], which in turn increments the array lengths to 2; for a third error, msg, url, and lno are assigned to msgArray[2], urlArray[2], and lnoArray[2], incrementing the array lengths to 3; and so on.

myOnError( )'s concluding return true; statement plays no role in the collection of error information; rather, its purpose is to suppress the browser's default notification mechanism for the detected errors - it can be removed if you don't feel the need to do this.

Example 3 displays its error information via the code below:
function displayErrors( ) {
   win2 = window.open('', 'window2', 'scrollbars=yes');
   win2.document.writeln('<b>Error Report</b><p>');

   for (var i = 0; i < msgArray.length; i++) {
      win2.document.writeln('<b>Error in file:</b> ' + urlArray[i] + '<br>');
      win2.document.writeln('<b>Line number:</b> ' + lnoArray[i] + '<br>');
      win2.document.writeln('<b>Message:</b> ' + msgArray[i] + '<p>');
   }
   win2.document.close( );
}
The displayErrors( ) function opens a new window and codes therein an Error Report that catalogs myOnError( )'s error information. Appropriately, myOnError( )'s array holdings are written to the new window's document via a for loop. Each loop iteration prints out an 'error block': in order, the file URL, line number, and message for a detected error, with a corresponding label - Error in file:, Line number:, and Message:, respectively - prepended to each value. Formatting-wise, the error blocks are given a double-spacing separation via p elements, whereas within each block the lines are given a single-spacing separation via br elements.

Somewhat curiously, Netscape applies the above functions not to a conventional script but to event handler commands in the example's document body code:
<body onload="noSuchFunction( );">
<form>
<br><input type="button" value="This button has a syntax error"
onclick="alert('unterminated string)">

<p><input type="button" value="Display Error Report"
onclick="displayErrors( );">
</form>
(1) The body element start-tag holds an onload attribute that calls a nonexistent noSuchFunction( ) function, which will throw a run-time error.

(2-3) The first-in-source-order input element's onclick="alert('unterminated string)" attribute could throw one or two syntax errors, depending on whether the browser perceives the ) right parenthesis character as (a) the end of the alert( ) command or (b) part of the alert( ) parameter string. In either case, you should see a "you're missing a closing single quote" type of error; in the (b) case, you might also see a "we're expecting a ) to close the alert( ) call" type of error.

In practice - September 2016 update

The div below contains an Example 3 demo: for best results, try it with either Google Chrome or Opera. In recasting my original example3demo.html demo as a self-contained div, I've replaced the <body onload="noSuchFunction( );"> HTML tag with a window.onload = noSuchFunction; JavaScript statement.

<title>Demo for Netscape's "Example 3: Error handling function"</title>




When I click the button, the Error Report in the new window duly displays an error for the window.onload = noSuchFunction; statement when using Firefox, Google Chrome, IE, Opera, or Safari. Firefox's return is:

Error Report

Error in file: http://reptile7.blogspot.com/2009/10/follow-error.html
Line number: 592
Message: ReferenceError: noSuchFunction is not defined

With Firefox, Google Chrome, and Opera, clicking the button and then reclicking the button adds to the report a second error for the alert('unterminated string) command. Google Chrome and Opera return:

Error in file: http://reptile7.blogspot.com/2009/10/follow-error.html
Line number: 594
Message: Uncaught SyntaxError: Unexpected token ILLEGAL

For whatever reason, Firefox reports that the second error occurs on the first line of the source:

Error in file: http://reptile7.blogspot.com/2009/10/follow-error.html
Line number: 1
Message: SyntaxError: unterminated string literal

Netscape's own Example 3 report lists three errors in the following order:
(1) an unterminated string literal error on line number 34 for the alert('unterminated string) command;
(2) a missing ) after argument list error on line number 34 for the alert('unterminated string) command; and
(3) a noSuchFunction is not defined error on line number 30 for the noSuchFunction( ); call.
To make a long story short, you'd have to go back to Netscape 3.x to generate this output; I am able to reproduce Netscape's report (the messages and the order thereof, if not their line numbers) when using Netscape 3.04, but not Netscape 4.61, in the SheepShaver environment. À la Firefox, Netscape 4.61 detects a single unterminated string literal syntax error for the alert('unterminated string) command.

BTW: When applied to the Primer #2 assignment script, Example 3 only reports a first-line syntax error with all of the browsers on my computer that support it.

In sum, Netscape's "Example 3: Error handling function" is of limited power and is certainly not a panacea for catching script errors, but it's not useless, either. If you had a document that incorporated five external scripts, and if there were an error in each script, then Example 3 - at least when using Firefox, Google Chrome, or Opera - would catch all five of those errors. And now that I think about it, Example 3 could - with some patience - be used to sort out multiple errors in a single script: Example 3 would catch the first error in a first run of the script; after fixing the first error, Example 3 would catch the second error in a second run of the script; and so on. At the end of the day, however, I'm not convinced that, as a debugging tool, Example 3 represents an improvement over (or, indeed, does any more than reproduce) the browser's error console.

Although there are other JavaScript error-related topics we could take up at this point (e.g., the throw and try...catch statements introduced in JavaScript 1.4, and also the core Error objects added to JavaScript 1.5), I would really rather move on to the next Beyond HTML : JavaScript tutorial, "So, You Want A JavaScript Clock, Huh?", which we'll go over in the following entry.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)