A great toolkit like Dojo deserves great tools alongside it. If you're used to chasing down problems with alert() and trial-and-error, it's time to give your development environment an upgrade!
Dojo itself has facilities for easing debugging tasks: an isDebug flag for better tracking down internals and console.debug() statements for logging. We'll cover these in the next sections, plus give you some hints on general JavaScript debugging.
Developing AJAX based applications, whether you use the Dojo Toolkit or develop everything the hard way from scratch, can pose quite a challenge to most developers. The difficulties typically arise from two main issues:
This article presents common problems and how currently available tools might be used to debug them. This section is not intended as an all-encompassing debugging guide for JavaScript problems.
Developers who have worked primarily with compiled languages will miss the compiler when working with a completely interpreted language like JavaScript. More often than not, the browser's error message is far from helpful in determining the actual root cause of the error. In addition, the errors reported by many AJAX toolkits are often not very helpful in
determining the root cause of the error. For example, if you have written a custom
widget based on the Dojo Toolkit that contains a syntax error and attempt to load it, you might get the following error:
FATAL exception raised: Could not load 'some.package.name.WidgetName'; last tried '__package__.js'
Unfortunately, the message does not tell you what the problem was, only that it could not load a particular widget. This error can be caused by many programming errors, but the most common ones are syntax errors in the widget JavaScript. The most common
syntax errors that cause the above error are as follows:
Note: All Dojo Toolkit widgets and extension widgets are JavaScript objects and therefore any custom widgets must use the proper comma separator between properties of the object (these include function declarations as properties).
You can avoid syntax errors by running a lint processor that understands JavaScript syntax on your code as you develop it. The lint processor will check for syntax errors before the code is run. Some of the JavaScript lint processors available on the web include:
Most lint processors are excellent at catching the errors mentioned previously and more. Many of the lint processors also enforce that JavaScript program statements always line terminate with ';' . While terminating with ';' is considered optional in JavaScript, it is highly recommended to do it for strictness and uniformity.
In summary, using lint syntax checking will save you hours of development time and frustration when trying to find the misplaced comma, malformed function, or missing closure.
Assuming that all the syntactical errors were caught, by running a lint processor on the JavaScript code, and corrected the next set of problems are all related to runtime problems. These issues tend to be tricker to debug, as the various browsers do not report errors in the same way. Unfortunately, this means that, as a JavaScript developer, you must
become familiar with debugging tools and browser error reporting mechanisms that are specific to each of the major supported browsers on which your application will be used. The list below outlines how some of the more well-known browsers report errors:
The most common problems encountered at runtime tend to be:
This is the correct way:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #000066; font-weight: bold;} .geshifilter .kw2 {color: #003366; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .co1 {color: #009900; font-style: italic;} .geshifilter .coMULTI {color: #009900; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #3366CC;} .geshifilter .nu0 {color: #CC0000;} .geshifilter .me1 {color: #006600;} .geshifilter .re0 {color: #0066FF;}The dojo.require() method of the Dojo loader uses a combination of XHR plus the eval statement to load JavaScript. This is one of the most powerful features in Dojo, however, it raises a few problems with some tools. First, most tools have no way to identify the source of the code. The information about the file or URL source of the buffer passed to eval in the Dojo loader is lost. (Note: the loader puts this metadata at the very bottom of the buffer, which may be inspected or parsed by some tools) Second, the Mozilla/Firefox console as well as most debuggers based on Mozilla's Spidermonkey engine suffer from a serious bug which makes debugging Dojo nearly impossible: all code loaded through an eval statement are identified at the location of the eval statement itself instead of the eval buffer. Not only are you presented with the wrong buffer for the stack frame, but the line number is also incorrect -- it is calculated as the offset of the eval command in the code plus the offset of the line within the eval buffer itself.
Neither Firebug nor Venkman work very well given the Spidermonkey limitation. Thankfully, there is an experimental patch available to Firebug which addresses both of these problems. Unitl then, setting debugAtAllCosts in djConfig can help better identify the error. Alternatively, you can [SCRIPT] include the JavaScript files directly on the page, but that can be very tedious.
If you are having weird problems with Firefox, it is often worthwhile running Firefox in safe mode. This is because installed extensions can interfere with the DOM tree, CSS, or even with javascript. In Windows there is a shortcut to start Firefox in safe mode from within the Mozilla Firefox folder, from the Start button.
Javascript has a debugger keyword that forces a breakpoint to occur. Just insert debugger; and if you have a debugger for your browser, then it will stop at the debugger keyword.
This is especially useful when using Venkman, because otherwise it can be difficult to get Venkman into debugging mode (e.g. you try to click on a line of source and it puts in a [F] future breakpoint).
It also works with Firebug and most other JavaScript debuggers.
There's also a lint program which catches a variety of problems in source files, but also flags certain patterns which are valid JavaScript, but considered by the author to be bad style.
Performance problems are bugs too, and Dojo has built-in facilities for identifying slow-running code segments. Some JavaScript debuggers like Firebug give file-loading performance, but often you need information at the code level.
You can cheaply calculate function execution time by taking the difference between two JavaScript dates. It's not a great technique, because you have to make educated guesses as to where the inefficient areas are, and it may take quite a lot of work to home in on the problem area. But it is easy to do if you are measuring a single function:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #000066; font-weight: bold;} .geshifilter .kw2 {color: #003366; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .co1 {color: #009900; font-style: italic;} .geshifilter .coMULTI {color: #009900; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #3366CC;} .geshifilter .nu0 {color: #CC0000;} .geshifilter .me1 {color: #006600;} .geshifilter .re0 {color: #0066FF;}Another example of code to do this is on this page.