Native JavaScript: sync and async

One of the most powerful parts of JavaScript is that it allows you to code synchronous (serially executing) code along side asynchronous code. But what is powerful also leads to more complication for a variety of common tasks. I’m going to explore and propose an addition to native JavaScript that I believe will help developers in negotiating async code tasks within a sync code base.

(note: If you already understand the problems with nesting callbacks for handling async code, and want to just get to the main point and skip over all the boring back-story, read my proposal)

What I’m going to be talking about is a complex and emerging topic with some specific descriptors attached, like “promises” and “defer”. It’s been pushed heavily recently by the server-side JavaScript community (CommonJS), but I think the usefulness of these concepts is just as valid in browser JavaScript. In fact, one major motivator for this exploration is the desire to design a pattern for sync/async coding that is useful in both contexts, so that more code can be written once and re-used.

However, I want to leave aside some of the formalities of the promise/defer conversation (mostly because I am by far not an expert on it) — I know just enough about them to be dangerous but probably not enough to be useful. I also want to try and separate opinions/preferences about syntax (although part of the goal is shorter/cleaner syntax) aside and talk mostly about the structural/functional needs. It’s impossible to talk only about the theory, so there will be a syntax I suggest, but I hope that the conversation that develops around my proposal isn’t side tracked by the “weeds” of syntax before we’ve thoroughly talked about the underlying behaviors.

There’s a rather long gist about my explorations of the idea if you’re interested in seeing the back-story to this post. I think especially interesting is the comment thread with some really good feedback from several people, including the venerable Brendan Eich himself (hint: he invented JavaScript).

A callback in your callback so you can callback

Almost universally, the common pattern in JavaScript for dealing with asynchronous coding is the idea of the callback. That is, taking advantage of the first-class status of functions, passing a reference of a function to an async mechanism, asking for the function to be “called back” when the asynchronous process finishes. But most anyone who’s ever written mid-complexity (or more) code with async functionality has run into several common problems with the callback pattern for async handling. At its most basic definition, what I’m trying to do here is come up with a better way to handle such tasks. Of course, it goes much deeper than that, but that’s probably the best mental place to start.

Let’s first take a look at some example code written in the traditional callback style to illustrate some of these issues:

function xhr(url, callback) {

var x = new XMLHttpRequest();

x.onreadystatechange = function(){

if (x.readyState == 4) {

callback(x.responseText);

}

};

x.open("GET",url);

x.send();

}

setTimeout(function(){

xhr("/something.ajax?greeting", function(greeting) {

xhr("/else.ajax?who&greeting="+greeting, function(who) {

console.log(greeting+" "+who);

});

});

}, 1000);

OK, so in this code, we want to wait 1 second (why? who cares!) and then we want to fire off an Ajax request to get some content. Next, we use that content to make a second Ajax request. Finally, once we have both pieces of content fetched, now we print them out to the console.

Firstly, the syntax ugliness of nesting callbacks 3 levels deep illustrates the inefficiency of this pattern. We accept that this is status quo, but in reality, I think this is an example of how the language is not properly (natively) supporting the common programming patterns found in modern usage of the language. We’re having to hack around with ugly, complicated, and thus harder-to-maintain syntax because that’s basically our only direct option.

Now, let’s consider what happens if I want to take that functionality and make it into some sort of general, reusable piece of code. There’s a few different ways this can be done:

function doSomethingCool(url_1, url_2, callback, delay) {

setTimeout(function(){

xhr(url_1, function(greeting) {

xhr(url_2+greeting, function(who){ callback(greeting, who); });

});

}, delay);

}

doSomethingCool("/something.ajax?greeting",

"/else.ajax?who&greeting=",

function(greeting, who) {

console.log(greeting+" "+who);

},

1000

);

Page 1 of 6 | Next page