What I have to talk about here is not going to be earth shattering, but it is a technique that has proved useful in a few different sites and scenarios for me. In fact, I regularly get questions regarding advanced use cases for LABjs (a parallel JavaScript loader), and invariably it comes back to something along these lines.

If you already understand object/function call chaining, just skip down to the good stuff.

The chains that bind you

Just so we’re all on the same page, “chaining” is this wonderful functional property of languages like JavaScript (which treat a function as a first-class citizen). It essentially amounts to making a function call, and the return value from the function is itself either another callable function, or more often, an object that has functions which are directly callable.

jQuery is probably the most prevalent use of this concept. Some example jQuery code:

$("p.neat").addClass("ohmy").show("slow");

In this snippet, $(…) is actually a function call, just like foo(…) or doSomethingReallyEvilButDontTellAnyone(…) (just kidding; only Google would name a function something crazy like that).

The return value from the $(…) call is an object, that has a bunch of properties on it, many of whom are functions. Consider that conceptually an object is returned like this (not actual code):

function $(...) {
   // do something cool
   return {
      addClass:function(...){...},
      show:function(...){...},
      ...
   };
}

So, what happens is that when that object is returned from the function, JavaScript will allow you to immediately de-reference the return value (the object), and using “.” (dot notation), access its properties. So $(…).addClass(…) makes the first chained call (“addClass”) off the return value from $(…). Then, addClass(…) also returns the same (same kind, not identical) object, and so this second return value can identically be de-referenced and a chained function be called. I like to refer to each chained function call as a “chain link”.

This chaining can theoretically go on forever (although for code readability it can be argued that 3 or 4 chain links is probably the most you want to practically do in production code, exceptions aside).

Why chains?

Probably the single biggest argument for developing code API’s that are of this chaining style is to pass context along from one function call to another in an automatic and graceful feeling way. For instance, in jQuery’s case, the reason for chaining is that internally, there’s a collection (a fancy array) of objects, and as each chained function is called, internally it loops over the collection of objects and performs tasks (such as expanding/contracting the collection, modifying objects in the collection, etc).

jQuery could work functionally this way and achieve the same effect:

var collection = $("p.neat");
$.addClass(collection,"ohmy");
$.show(collection,"slow");

See how we had to pass in the “collection” object/array for every function call? It works, but that code is arguably a little less graceful. And certainly it’s a little more repetitive.

So, chaining was a way to accomplish the same task (context passing across function calls) but in a prettier, more graceful fashion. Generally, the idea of adjusting the way a set of code works to make it more expressive or pleasant is called adding “syntactic sugar”.

To be fair, syntactic sugar is not the only reason why chaining in functional languages is useful. In fact, with LABjs, which also has a similar type of chaining API (although internally operates quite differently from jQuery), the reasons were only partially “sugar”; chaining in LABjs’ case actually provides an effective solution to guard against certain types of race conditions.

Because of how JavaScript (single-threaded) works, a chain of function calls is more or less guaranteed to complete fully before any other code comes in and interrupts to execute. This is also probably true of a series of distinct function calls in a single code block, but even more definitely so for a chain of function calls or (as we’ll see in a moment), a loop of function calls.

So why not a chain?

Since chains are powerful and also tend to lead to more expressive code (unless abused) and also generally less code, you may wonder, why wouldn’t we always use chains for everything?

The obvious: some function calls are, by their nature, independent and thus do not need to (or should not!) share a context. Also, under certain circumstances, chaining can be less efficient internally, depending on how the context is stored/shared/used.

Let’s face it: if you really want to write your entire “program” on one line with a bunch of obscure/abusive syntactical tricks, just go write some Perl. I kid, I kid.

But beyond those things, one fundamental fact of chaining is that it’s not “dynamic”. Basically, what I mean by this is that you pretty much hard-code at the time of code writing (aka, “build time”) how a chain is constructed. You can’t decide at run time based on environmental conditions that some parts of the chain are conditionally not executed (like by wrapping them in an if-statement, etc).

The ability to do that kind of run-time logic is restricted syntactically to individual statements/function calls, so a chain will be considered an atomic single indivisible unit for those purposes. You could conditionally decide whether to run one of several different chains depending on conditions, but each chain to be chosen would be pre-defined and for the most part immutable.

So, the truth is, chaining provides a syntactically prettier (more expressive) code approach, but it limits us a little bit in terms of coding flexibility.

I need more concrete

To illustrate, let’s revisit jQuery’s example code from above. Let’s say instead that what you really want to do is only run the addClass(…) call if some condition is true (like for instance, the user has a valid login session, or whatever). So, you want to basically do conceptually something like this:

$("p.neat")
if (userLoggedIn()) {  .addClass("ohmy")  }  // invalid syntax; will not work!
.show("slow");

As I mentioned, you could just have two different chains, one with addClass(…) in the chain, one without it, and choose which chain to execute with your if-statement. This leads to more and repetitive code; a bad thing. DRY (don’t repeat yourself).

And to be honest, you could also model this in a pure jQuery way (only in the chain using various filters), a variety of different ways. For instance, something like this (while ugly) might work:

$("p.neat")
.filter(function(){
   return isLoggedIn();
})
.addClass("ohmy")
.end() // ends the most recent filtering operation
.show("slow");

What I did here was use filter(…) to basically conditionally empty out the internal collection if not logged in (by returning false for all iterations), meaning the addClass(…) call is essentially ignored, and then revert back to my original collection with a .end() call before lastly calling .show(…).

Let me be clear: while you can do it this way, this is by far not the most efficient or code-friendly way to do so. This would be an example of an anti-pattern, where you are abusing jQuery’s syntax to solve a problem in a way that it should not be solved. It goes contrary to the spirit of jQuery (“write less, do more”).

Other examples?

Conditional inclusion of “chain links” is only one scenario where traditional chaining is kind of limiting. What if you want to be able to piece together different parts of a chain from various different snippets of code across mutliple functions? This may sound strange, but with complex Web 2.0 web applications, this kind of thing is not uncommon. And it flys in the face of the simple syntactic sugar that chaining is supposed to give us.

Nor are these problems limited to jQuery. With LABjs for instance, a chain might look like this:

$LAB
.script("framework.js")
.script("loggedin.js")
.wait(function(){
  // do something
});

Notice there I may want to only load “loggedin.js” if the user is, in fact, logged in. Same syntactic problem as above. But LABjs has no conditional “filters” that can modify the chain’s context, so we have less options (which in this case is a good thing!)

Or, what if I have a CMS system (like Wordpress for instance) that, across various functions, files, templates, etc, needs to load up a variety of different files, all based on various different environmental conditions and which templates are active, etc. Could I do individual $LAB chain calls in each location? Yes. But then I lose the ability to sequence the loads (ensure execution order). Also, it’s less memory efficient to do 8 different chains with 1 script in each, as opposed to one chain with 8 scripts in it.

Or, what if I want to use LABjs in a larger solution for creating robust fallback for resource loading from CDN locations? I need to conditionally decide during loading/run-time if I need to add more scripts to the “queue” because one load failed. Not possible with traditional chaining.

Unravel the ball of yarn

All this leads up to say that chaining is great and expressive and powerful, but it’s not complete for all our needs. So, we need to get a little more creative in those cases. And this technique is what I’m going to call “Simulated Chaining”.

Recall that at the top of this post, we talked about how chaining works because the return value from a function is either a function itself (and thus can be called directly), or it can be an object that can be de-refenenced and has properties which are functions to be executed.

So, our solution lies in that sentence (emphasis added). The return value from a function can either be used immediately, or it can be stored and used later. This isn’t anything new; if you’ve ever called any function in any language, you know it can return a value that you can store in a variable. What might have escaped you until now is that this return value that you store can be a contextually sensitive object that would otherwise have been used immediately in a chaining situation. And the cool part is it can be used later (like the next loop iteration) to pick up where the chain left off.

So, instead of pre-defining a chain in our code/build-time, we can instead programatically (at run-time) build up a “list” (an array/queue for instance) of functions to be called, and then “simulate” a chain by looping through the list, calling each function, and storing the return value for use in the next iteration.

For instance, the LABjs script code above can be done like this instead:

var queue = []; // empty array for now
...
queue[queue.length] = "framework.js";
...
if (isLoggedIn()) { queue[queue.length] = "loggedin.js";
...
var $L = $LAB;
for (var i=0, len=queue.length; i<len; i++) {
   $L = $L.script(queue[i]);
}
$L.wait(function(){
   // do something
});

I simulated a chain of function calls with an iterative for-loop. (NOTE: this is conceptually very similar to how you might take what would otherwise be a recursive set of function calls and turn it into a non-recrusive, iterative loop instead, like for performance reasons). The key is: store the return value from a function call, and then use that stored value as the object that makes the next call. Plain and simple. And now more powerful as you can build up your chains at run-time in as complex a way as is necessary.

Theoretically, a very similar approach could be taken for the jQuery examples above. However, I’ll leave that as an exercise for the reader.

Let’s look at one last slightly more advanced example of how to use simulated chaining with LABjs (which is nearly identical to how I do it on several of my sites):

var queue = [];
...
if (conditionOne()) {
   queue.push("framework.js",false); // false will create an empty .wait()
}
...
if (conditionTwo()) {
   queue.push("plugin1.js","plugin2.js",function(){
      // initialize plugins
   });
}
...
queue.push("mypage.js");
...
var $L = $LAB;
for (var i=0, len=queue.length; i<len; i++) {
   if (typeof queue[i] === "function") $L = $L.wait(queue[i]);
   else if (queue[i] === false) $L = $L.wait();
   else $L = $L.script(queue[i]);
}

I specify a queue array that can have one of three types of entries: a [string] is interpreted as a script to load, a [false] is interpreted as an empty .wait() call, and a [function] is passed to a .wait(…) call. I can use any manner of complex logic to build up the queue, and then in one for-loop at the bottom of the page, simulate the chain by looping over the queue.

Hopefully this helps clear up some of the mysticism that is chaining and give you some other ways to approach the challenging use cases you may face in your code. Go forth and chain (or loop)!

Bookmark and Share

This entry was written by getify , posted on Wednesday February 10 2010at 10:02 am , filed under JavaScript and tagged , , , , . Bookmark the permalink . Post a comment below or leave a trackback: Trackback URL.

One Response to “Simulated Chaining in JavaScript”

  • metalculus84 says:

    First off, this is great. Aside from conditional loading of scripts, if you are developing a big application with templates and sub templates you will want to be able to extend the queue on subtemplates. This makes that possible. Have you thought about introducting at least conditional loading to the api in a slicker way?

Leave a Reply

Consider Registering or Logging in before commenting.

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Switch to our mobile site