The new script loader component – part I

The latest release of the MS AJAX library introduces a new object known as the script loader component. The script loader adds several new interesting features to the library. Here’s a few:

  • ensures proper ordering of the JavaScript files;
  • allows lazy loading of files;
  • allows you to enrich the Sys object with information regarding features introduced by each JavaScript file (ie, it augments the Sys object with properties that allow you to simplify the code used for creating several kinds of objects).

You can access the script loader through the Sys.loader object. Adapting a JavaScript file to be used by the Sys.loader object is simple and relies on two steps (you can reduce it to one, but note that using these two is the recommended approach – more info at the end of the post):

  • you need to identify the features of a specific script. This is done by passing a JavaScript literal object  to the Sys.loader.defineScripts method. This object will, for instance, specify the dependencies of the current script which can be used later for ensuring the download of the necessary files needed for a specific feature introduced by this script;
  • all the scripts that support lazy loading are supposed to notify the script loader when they’re loaded. This is achieved by invoking the Sys.loader.registerScript method;

Here’s how you might define a script (I’ll just copy an example from the samples here):

Sys.loader.defineScripts({
    releaseUrl: "%/../ACT/" + "{0}.js",
    debugUrl: "%/../ACT/" + "{0}.js"
},
    [
        { name: "ACTWatermark",
            executionDependencies: ["ACTExtenderBase"],
            behaviors: ["AjaxControlToolkit.Watermark"],
            isLoaded: !!(window.AjaxControlToolkit && AjaxControlToolkit.Watermark)
        },
        { name: "ACTExtenderBase",
            executionDependencies: ["ACTCommon"],isLoaded: !!(window.AjaxControlToolkit && AjaxControlToolkit.ControlBase)
        },{ name: "ACTCommon",
            executionDependencies: ["ComponentModel", "Globalization"],
            isLoaded: !!(window.AjaxControlToolkit && AjaxControlToolkit.TextBoxWrapper)
        }
    ]
);

The defineScripts method expects two parameters:

  • the first is a literal object with predefined values that will be used when the script info objects passed in the second parameter don’t have that property set up;
  • the second is an array of script objects with information about each script.

In the previous example, we’ve defined three scripts and named them ACTWatermark, ACTExtenderBase and ACTCommon. As you can see, the property executionDependencies specifies the execution dependencies needed for guaranteeing the proper behavior of the script. Script info objects expose several interesting properties, but we’ll leave its study for a future post.

As I’ve said, signaling the loading of a script is done through the registerScript method. Here’s an example taken from the samples:

(function() {
function execute() {
Type._registerScript(
"ACTCommon.js",
["MicrosoftAjaxComponentModel.js", "MicrosoftAjaxGlobalization.js"]); Type.registerNamespace(''AjaxControlToolkit'');
AjaxControlToolkit.BoxSide = function() { }
//library code goes here } if (window.Sys && Sys.loader) { Sys.loader.registerScript("ACTCommon", null, execute); } else { execute(); } })();

I’ve removed most of useful the code of the library (I’ve only left the _registerScript call that marks the beginning of that code) because I wanted to concentrate on the registration process. As you can see, preview 6 is using JavaScript recommended practices for ensuring that the global namespace isn’t polluted (that’s why they’re wrapping everything in an anonymous function which is executed in “the spot”).

For the current discussion, the most important part of the occurs when the Sys.loader.registerScript method is called. Currently, the method expects three parameters:

  • the first, identifies the name of the current script that can be process. This will be used internally for getting a reference to a  script info object previously defined through the defineScripts method and see if any additional script downloads are necessary for the proper behavior of this script. Notice that processing (ie, interpretation of the “real” code defined on the script will only happen when all the dependencies are loaded);
  • the second, lets you specify an array of execution dependencies needed for the proper working of the “current” script (most of the time, you’ll set this parameter to null – more info below);
  • the third parameter lets you pass a reference to a callback function that will be invoked when all the dependencies have been loaded.

At the beginning of this post, I said that configuring the scripts required two steps: defining the script (by invoking the defineScript(s) method) and signaling its loading (through the registerScript method). To be honest, this is the recommended approach (at least, it’s used in most places in the library) and is the one which will let you completely define the script you’re defining (it lets you indicate plugins, components, dependencies, execution dependencies, composites, etc – again, this is too much for a simple post and we’ll come back to this in the future).

However, if you’re not interested in specifying any of those features, you might get away with using only the registerScript method. The samples show that (currently) this is only done by the MicrosofAjaxWebForms script. Here’s how it uses the the registerScript method:

Sys.loader.registerScript(
"WebForms",
["ComponentModel", "Serialization", "Network"],
execute);

If you compare this with the previous registerScript snippet, you’ll see that we’re specifying the execution dependencies (array of strings passed in the second parameter). Since the “WebForms” script hasn’t been defined previously (ie, there’s no defineScripts call for it), the script loader object will use this information to load the script files identified by the indicated names. Even if the defineScripts method would have been invoked for this script, the scripts passed through registerScript’s second parameter would end up being added to the existing list of execution dependencies.

As I’ve said above, the third parameter identifies a callback method which will be called when all the dependencies have been loaded. If you look carefully at the registration snippet, you’ll see that the “real” definition of the library is inside a function called execute which is also configured as the callback function! Since the callback function will only be invoked when all the dependencies are loaded, that means that the “real code” will only be executed when all the needed dependencies are loaded. Pretty cool, right?

And that’s it: by following these two easy steps (this is the recommended approach only) you’ve configured your script to be used by the script loader object. There’s really a lot to be said about the features and we’ll come back to them in future posts. Stay tuned for more on MS AJAX.

Advertisements

~ by Luis Abreu on October 16, 2009.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: