Wednesday, December 14, 2011

[js] Closure blocks

I haven't really come across much specifically about this, but making use of anonymous functions as callbacks to your asynchronous routines allows you to format these calls so that they look (and behave) like a regular structured block.

Asynchronous calls are, of course, a fact of life with AJAX, but they come up in other situations as well, like waiting for user input. Consider two approaches to the same functionality.

function getRec(id) {  // request
  showWorking(true);
  ajaxFetch(id);
}
function getRec_callback(rec) {  // receipt
  showWorking(false);
  displayRec(rec);
  // more stuff
}

/* Ajax */
function ajaxFetch(id) {
  var rec = // ..etc
  getRec_callback(rec);
}

In the above approach the request and receipt are split across two functions, getRec and getRec_callback, spanning the dreaded "asynchronous gap."

Here's another approach:

function getRec(id) { // request
  showWorking(true);
  ajaxFetch(id, function(rec) {  // receipt
    showWorking(false);
    displayRec(rec);
    // more stuff
  })
}

/* Ajax */
function ajaxFetch(id, callback) {
  var rec = // ..etc
  callback(rec);
}

The request and receipt are again split into two functions (this can't be avoided), but the use of a closure for the receipt allows us to combine both into getRec, and offers at the very least the appearance of a seamless flow of logic, from request to receipt.

But there's more than aesthetics at play here when you consider that Javascript closures can access the local variables of the enclosing function. This means any variables defined in the request block, prior to the asynchronous jump, will still be available and ready for use in the receipt block, after the asynchronous jump. So it not only looks like a nested block of code, it behaves like a nested block of code. And we have bridged the asynchronous gap.