My favorites | Sign in
Project Home Downloads Wiki Issues
Search
for
HandsOn  
Updated Feb 12, 2010 by aubourg.julian

Hands on Dominoes

Dominoes as a simple script loader

At its core, Dominoes is a javascript file loader. For instance, if you wish to execute some code that is dependant on the very popular jQuery framework, you would write something like this:

dominoes( "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" , function() {
    // Your jQuery dependant code goes here
} );

One thing that Dominoes ensures is that the same script won't be loaded twice so, if you have the following code later on:

dominoes( "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" , function() {
    // Some other code also dependant on jQuery
} );

The function will get executed right away since jQuery has already been loaded.

Dominoes also detects when a request is made for a script that's already being loaded. So the two lines of codes above could be following one another and this wouldn't cause any trouble (and jQuery would still be loaded only once).

Another thing Dominoes can do for you is when you need to load a script regularly because it's updating some DOM elements. By default, Dominoes would load it once and never do it again, but you can use the following syntax to get around the caching mechanism:

dominoes( {

    url: "http://mySite.org/js/updateUserTable.js",
    cache: false

} , function() {
  // Some code here, eventually
} );

Dominoes as a stylesheet loader

Dominoes can also load css stylesheets and will ensure the stylesheet has been properly loaded and applied before executing more code:

dominoes( "$css(http://mysite/path/stylesheet.css)" , function() {
    // The stylesheet has been loaded and applied
} );

Like for scripts, Dominoes detects when a request is made for a stylesheet that's already being loaded.

Dominoes as a substitution engine

Writing urls can be cumbersome and Dominoes can help you there.

Say most of your javascript scripts reside within "/u/kio/67/long/is/long/js/". Talk about typos in perspective. With Dominoes, you could do something like this:

dominoes.property( "mySiteJSPath" , "http://mySite.org/u/kio/67/long/is/long/js" );

Then use this new-born property as follows:

dominoes( "$(mySiteJSPath)/script1.js" , function1 );
dominoes( "$(mySiteJSPath)/script2.js" , function2 );

The substitution engine is even recursive, so it would be quite easy to handle subdirectories:

dominoes.property( "mySiteGeolocPath" , "$(mySiteJSPath)/geoloc" );
dominoes.property( "mySiteAjaxPath" , "$(mySiteJSPath)/ajax" );

dominoes( "$(mySiteGeolocPath)/map.js" , geolocRelatedCode );

dominoes( "$(mySiteAjaxPath)/requests.js" , ajaxRelatedCode );

Dominoes as a dependency engine

Take the following example:

dominoes( "$(jQueryURL)", "./js/myScript/js", myFunction );

The problem here is that myScript will only get loaded once jQuery has been received entirely. This is quite inneficient if and when myScript does not use anything in jQuery. Thankfully, you can write the following:

dominoes( "$(jQueryURL) ./js/myScript/js" , myFunction );

What the code above means is: "load jQuery & myScript in any order you like, then call myFunction".

Dependency rules

In fact, Dominoes provides a crude syntax to describe dependency rules:

action1 action2 action1 & action2 are independant
action1 > action2 action2 depends on the completion of action1
action1 >| action2 action2 depends on the completion of action1 and on the DOM being ready for manipulation
( sub-rule ) sub-rule (the completion of this action is determined by the completion of the whole sub-rule)
(( optional-sub-rule )) optional sub-rule (same as a normal sub-rule but the completion of this action is not needed down the line, i.e. fire & forget)

Let's take a big, daunting, example to make things clear (hopefully):

( action1 > action2 ) action3 > (( action4 > action5 )) action6 >| action7

What we're expressing here is this: action2 depends on action1. Once action3 & action2 are done, we can get to the next group: here action4 & action6 can start. Since the "action4 > action5" rule is optional, action7 will be performed as soon as action6 is finished (provided the DOM is ready for manipulation).

Still here? Because you may wonder what is meant by actions here. So here is an example with a syntax we haven't talked about yet:

dominoes( {

    chain: "$(JSON) $(jQuery) $(swfObject) > initCode >| domManipulation",

    initCode: function() {
        // Some library initialization code here
    },

    domManipulation: function() {
        // DOM manipulation here
    }

} );

As you can see, once you define your rule as the chain attribute of an object litteral, the expression is parsed in the context of this litteral, thus making the initCode and domManipulation methods available.

Rules repository

Let's add some difficulty: first, let's say we want to run some code once jQuery is loaded. If we do:

$(JSON) $(jQuery) > jQueryInitCode $(swfObject) > initCode >| domManipulation

swfObject won't be loaded before jQuery and its init code are done. So we must use a sub-rule:

$(JSON) ( $(jQuery) > jQueryInitCode ) $(swfObject) > initCode >| domManipulation

But this makes the expression quite long now. Thankfully, we can write it like this:

dominoes( {

    chain: "$(JSON) jQuery $(swfObject) > initCode >| domManipulation",

    jQuery: "$(jQuery) > jQueryInitCode",

    jQueryInitCode: function() {
        // jQuery specific init code goes here
    },

    initCode: function() {
        // Library initialization code here
    },

    domManipulation: function() {
        // DOM manipulation here
    }

} );

or even:

dominoes( {

    chain: "$(JSON) jQuery $(swfObject) > initCode >| domManipulation",

    jQuery: { 

        chain: "$(jQuery) > initCode",

        initCode: function() {
            // jQuery specific init code goes here
        }
    },

    initCode: function() {
        // Library initialization code here
    },

    domManipulation: function() {
        // DOM manipulation here
    }

} );

Now that could be a lot to write, especially if you have a lot of code depending on jQuery. However, Dominoes offers a repository for rules, so you could do something like this:

dominoes.rule( "jQuery" , "$(jQuery)" , function() {
    // jQuery specific init code goes here
} );

dominoes.rule( "JSLibs", "$(JSON) jQuery $(swfObject)" , function() {
    // Library initialization code here
} ) ;

// And later on...

dominoes( "JSLibs >|" , function() {
    // DOM manipulation here
} );

Note how we dropped the object litterals syntax for a more straightforward arguments list. Note also that the function in the jQuery rule will only be ran once. This is a big advantage of defining named rules: they act like urls and are a one-time only occurence.

Further Dominoes

That's it for this hands on. You may go to Advanced Techniques if you wish to explore Dominoes further.

Comment by nevstokes, Feb 12, 2010

I was a little confused when I updated from the alpha until I noticed that things that used to be ${JSON} have become $(JSON) - there is still an example of the old style in the description of the sub-rule in the "Rules repository" section that may confuse: ${swfObject}

Thanks for your work on this, it's proving to be fantastically useful. The cumulators are exactly what I was trying to work out how to implement in the alpha!

Comment by aubourg.julian, Feb 12, 2010

@nevstokes: corrected, thanks for having pointed out the typo :)

Comment by alberto....@gmail.com, Jun 17, 2010

Hi, Julian.

I didn't understand if its possibile to handle request erros. What happens if you call an invalid url?

Thank you very much for this and... keep up the great work!

Comment by aubourg.julian, Jun 17, 2010

@alberto: no, handling request errors is beyond the scope of dominoes. If one request fails within a chain, then the whole chain will halt which is enough for a script dependencies loader/manager.

And thanks for the kind words, always appreciated :)

Comment by nevstokes, Jul 5, 2010

I seem to be having issues with getting Lightview to play nicely with Dominoes. Has anybody else encountered this?

Comment by aubourg.julian, Jul 5, 2010

@nevstrokes: never used Lightview. What happened exactly? Maybe you should open an issue.

Comment by nevstokes, Jul 9, 2010

Hey Julian,

Basically everything works if I include each file in a <script> tag but as soon as I try to use dominoes Lightview complains about not having a controller. A hefty segment of the Lightview code has been compressed with Dean Edwards packer - could this possibly be something to do with it?

Comment by aubourg.julian, Jul 9, 2010

@nevstrokes: oh yeah, Dean's packer is a nightmare for script tag injection based loaders. Sometimes it works, sometimes it does not.


Sign in to add a comment
Powered by Google Project Hosting