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, " ");
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
Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)