This other day I was just coding and stuff when it suddenly struck me – multithreaded programming! My general ideas about it always revolved around things like scalability, synchronization, and those philosophers who refuse to eat with their hands. What I completely missed was the human side of it – the way it helps developers express their thoughts in code with so much ease and elegance even when they’re not pursuing head-spinning performance. In fact, lots of multithreaded code out there has nothing to do with scaling up and is all about breaking down code into logical sections.
Core Javascript Multithreading
You’re probably thinking I’m way off here because everyone knows javascript is completely single-threaded. That’s right – those DOM events, AJAX, timed events – all executed by the same thread! (see John Resig’s article). The general idea is that javascript executes short-burst pieces of code and can afford to run all events in the same thread. By doing that, it avoids tricky synchronization issues and greatly simplifies the way we work with it.
AJAX and DOM events in javascript are a great example of using multithreaded paradigms (simulated multithreading that is) to simplify coding. The alternative would have been to write your own loop that does something like:
while(true){
runDOMEvents();
runScheduledEvents();
runAJAXRequests();
runEverythingElse();
}
Instead, the javascript runtime already does that for you, so all you need to do is supply the callbacks. In addition, it also runs each event with its appropriate call stack so the multithreaded illusion looks very real in firebug.
Dojo Promises
Building on the existing body of knowledge on futures and promises, Dojo defines the concept of a Deferred.You may have also seen this exact same concept in Python, or a very similar one in Java’s java.util.concurrent.Futures. Java Futures are literally running in a separate thread so getting the future value can afford to block. In Javascript otoh, no blocking is possible since there’s only one thread executing the whole shebang, so the alternative is to provide a callback to execute when the future value becomes available. This means the promised value always gets processed in a different call stack even though it’s all in the same physical thread. However, that’s not a big issue in Javascript since the concept of an execution context is extremely flexible thanks to functions like apply() and call() (or wrappers like dojo.hitch()).
You may have noticed that Java Futures already return an object of the expected type, so you can use the Future as a proxy for the concrete value. For example, we could invoke the process() method below using a String
process("abc");
or we can just as well give it a future String value:
Future<String> future = ... process(future.get()); // blocks until String is ready
The interface therefore remains uniform whether we use a Future or a concrete value. Since this is not the case in Dojo, we have a solid workaround for it in the form of dojo.when(), which does the extra work of normalizing promises and concrete values for us.