« JSManager.js - Easily manage JS dependancies
The best tool for the job is? »


Traversing a JavaScript Array Using Callbacks

My last blog post introduced a nifty little library called JSManager. I wanted to highlight a somewhat clever trick that is used to sequentially load registered JavaScript files.

Registered scripts are sequentially pushed into an array, and because I need to load them one after another to prevent conflicts, I can't simply iterate the array calling the load function:

// Would not work!

for (f in fileList)

{

   loadJSInclude(fileList(f).FileName, fileList(f).callBack);

}

That technique would attempt to load all scripts immediately, which could cause load-order conflicts, and make it impossible to figure out when they are all loaded.

I needed a better technique, and the concept that I came up with is iterating an array using callbacks.

/* Loads all registered JS Files, then runs the passed callback */

Init : function (callback) {       

    // Setup callback chain

    for (f in fileList) {                                                                   

        fileList[f].Callback = jsLoaderCallback(parseInt(f));               

        // Setup final callback

        if (f == fileList.length - 1 && callback != null) {

            fileList[f].Callback = jsLoaderCallback(parseInt(f), callback);

        }

    }                                       

    // Run the Chain

    fileList[0].Callback();                                           

}

This trick assigns a callback to each array element. Each callback performs the load operation, then calls the next callback in the array. The final callback is the "All Finished" callback provided by the user.

This allows me to iterate the array asynchronously, but only move to the next element when the previous one is completely done loading.

The actual callback function is this:

    // Used to register the callback chain

    function jsLoaderCallback(index, callback) {       

        return function () {                                            

            if ((index + 1) < fileList.length)

                callback = fileList[index + 1].Callback;

 

            if (fileList[index].Loaded == null) {

                fileList[index].Loaded = true;

                loadJSInclude(fileList[index].FileName, callback);                

            }

            else {

                callback();

            }

        };   

    }

The first thing you might notice is that this function simply returns a function. This is because of how javascript scopes closures and is usually called the "getRef()" trick. I'd recommend reading up on it to clarify this somewhat.

This technique could probably be generalized out into a handy set of pluggable functions, and I may do that in the future.

Posted by Jonathan Holland on 2/21/2009.

Tags: Tips-and-Tricks   Javascript

Comments:

This technique could probably be generalized out into a handy set of pluggable functions, and I may do that in the future.

I think I did something similar aeons ago:

http://www.reddit.com/r/javascript/comments/7z3xx/howtotraverseajavascriptarrayasynchronously/c07tdqx

Gravatar Posted by David on 2/22/2009.

Comments are closed on this post.