Analyzing Your Script

Modified on 2009/12/14 23:10 by Stephen Walther — Categorized as: Uncategorized

Because JavaScript is an interpreted language, and a type-less one at that, developers do not get the advantage of compile-time checks available to developers in other languages. It is a good idea to always run JavaScript sources through a lint-style checker before deployment. Douglas Crockford maintains a very good jslint application at his website (http://www.crockford.com/jslint).

Microsoft Ajax Minifier has a modicum of linting-style capabilities, but they will be increased over time. Using the -ANALYZE option on the command line will change the default warning level to show all warnings (which can be overridden with the –WARN option), and will spew a ton of analytical information for all the scopes in your code. It will list all the global object (variables and functions) defined by your code, then each function scope in order of its appearance in the code. Within the function scopes, each variable and function defined or referenced is listed, along with its status – argument, local, outer, global, etc. If local-renaming is turned on, it also lists what name that field has been renamed to, which is a good aid for debugging. If a function scope is marked as “unknown,” it will be noted in the analytical output, as will a status of “unreachable.”

Using the –ANALYZE option for Microsoft Ajax Minifier, you can find JavaScript coding problems before they cause actual bugs. In JavaScript, you can use variables without defining them – the runtime assumes they are properties on the global object, which is the window object within a browser. This is bad for performance reasons – instead of binding to a local variable when assigning to a variable that isn’t defined, an expando property is created on the window object. It is a very good idea to look at the analysis and ensure that all variables your code is referencing are defined within the proper scope.

function func(p,m)
{
    for(n = 2; n < m; ++n)
    {
	p *= n;
    }
    return p;
}

In the code snippet above, the window object will get an expando property named “n” created. Microsoft Ajax Minifier will output a warning for all global variables referenced but not defined. The developer should look at all these warnings and fix instances like the one above, where a local variable definition is called for.

JavaScript also allows you to redefine variables that were previously defined within the same scope, which could generate unexpected results and errors. JavaScript only has the global scope and function-level scopes. It does not have block-level scopes as languages like C and C# do. Take, for instance, this code:

function func()
{
    var n,a = "outer";
    for( n = 0; n < 10; ++n )
    {
        var a = n;
        // do something else
    }
    alert(a);
}

In C or C#, the alert function would be passed the string “outer,” but in JavaScript it would be passed the number 10. The JavaScript code is actually defining the variable, “a”, twice in this code snippet. This is not a runtime error in JavaScript – the second definition simply reuses the existing variable. But it may not generate the output the developer intended. Microsoft Ajax Minifier will display an error for all variables that are defined multiple times within the same scope. Developers should fix these bugs before shipping their code.

Various style warnings may be thrown as well. For instance, Microsoft Ajax Minifier will locate all single-statement blocks that aren’t enclosed in curly braces, and warn the developer that they should add them. This is because developers can sometimes unintentionally introduce bugs in their code by not liberally using curly-braces. Curly-braces also increase readability and maintainability. It is strongly encouraged that developers always enclose their blocks in curly-braces, especially since Microsoft Ajax Minifier will remove them where they aren’t necessary before their code gets deployed. Unlike jslint, Microsoft Ajax Minifier does not force any particular curly-brace coding style – separate-line or same-line – upon the developer (other than to use them).

In the future, Microsoft Ajax Minifier might also alert the developer to statements that don’t end in semi-colons – another possible source of runtime bugs. At the time of this writing, those alerts are not generated.

The format of the analytical output may change in the future to allow for better use by other tools like Excel. At the time of this writing, the output is always made as text to the standard output stream. A function scope will indicate which line the function begins on, then list all the variables and functions referenced within that function. If local-renaming is enabled and the function is known at compile time, what name the fields are renamed to is also listed:

Function AddForecastCallback - starts at line 2233 (renamed to s)
        context [argument] (renamed to k)
        response [argument] (renamed to g)
        cities [local var] (renamed to f)
        city [local var] (renamed to i)
        info [local var] (renamed to h)
        row [local var] (renamed to j)
        m_dataUrl [outer var] (renamed to l)
        m_gatorBinding [outer var] (renamed to a)
        m_itemList [outer var] (renamed to c)
        m_listEl [outer var] (renamed to b)
        m_searchbox [outer var] (renamed to d)
        m_this [outer var] (renamed to e)
        AddForecastCallback [outer function] (renamed to s)
        AddWeatherCity [outer function] (renamed to t)
        ParseWeatherResponse [outer function] (renamed to r)
        SetRowBorders [outer function] (renamed to o)
        Msn [global var]
        url [global var]
        document [global object]
        escape [global function]

In this particular example, the variable “url” is indicated as a global variable. If we were to check the errors returned, we will find this in the output:

Possible performance problem: Variable 'url' has not been declared
At line 2287, col 7-10: url

This is an example of an undefined variable that gets added as an expando property on the window object. Most-likely the developer intended this reference to be a local variable.

After the scope report, the Undefined Globals report is output if there are any undefined global variables or functions. This report will list every occurrence of a reference to a variable that was not defined within the scope chain and is assumed to be a global defined elsewhere. It is a very good idea to look at each and every one of these instances and ensure that the developer did not accidentally leave out a local variable definition, as it could be a performance bug – or worse.

 
Undefined Globals:
        DOMParser (Constructor) at Line 42, Column 20
        infopaneChooserForm (Variable) at Line 4196, Column 15
        infopaneChooserForm (Variable) at Line 4229, Column 14
        infopaneChooserForm (Variable) at Line 4240, Column 14
        infopaneClose (Variable) at Line 4200, Column 15
        infopaneClose (Variable) at Line 4233, Column 14
        m_itemList (Variable) at Line 3298, Column 4
        ppstatus (Variable) at Line 1505, Column 4
        registerNamespace (Function) at Line 1, Column 1
        url (Variable) at Line 2287, Column 7
        XMLSerializer (Constructor) at Line 50, Column 24

In this example, DOMParser, infopaneChooserform, infopaneClose, registerNamespace, and XMLSerializer are all objects or functions that I know are defined in other modules. However, m_itemList, ppstatus, and url should be local variables.