Deferred functions in Javascript
Okey dokey. So as my first little peek at some of the actual programming I’ve been up to over the past couple of years, here’s a little implementation of a way to defer arbitrary functions until arbitrary conditions have been met.
One of the first problems I came up against when developing Bxs came to light when I was figuring out how to build editable XUL listboxes for given MySQL tables dynamically at application startup, and then share information between them as they were building and after they were built.
Example: I have a table describing a list of exhibitions, each row having the usual stuff like title, dates etc., and also a field for the exhibition venue, which is a ‘has-one’ relationship to another table. I want the exhibitions listbox to display not the id number of the relevant venue, but the name of the venue and the city it’s located in. I want the app, as it’s booting up, to recognise that the given field relates to another table, check if the listbox for that table has built itself yet, and if so, to grab the relevant details from that listbox. If the related listbox hasn’t built, the requesting table tells it to build, waits until it’s built, etc.
The problem is: how do I tell the exhibitions listbox when the venues listbox has built?
The way I did it was using object.watch(). Here’s the implementation:
when = function(obj,prop,fn) {
if (obj[prop] && obj[prop] !== undefined) {
return fn();
}
if (!obj.deferredFunctions) {
obj.deferredFunctions = {};
}
if (!obj.deferredFunctions[prop]) {
obj.deferredFunctions[prop] = [];
}
obj.deferredFunctions[prop].push(fn);
var ready = function(newVal) {
obj.unwatch(prop);
obj[prop] = newVal;
obj.deferredFunctions[prop].forEach(function(el,idx,arr) {
var _fn = el;
arr[idx] = null;
return _fn();
});
delete obj.deferredFunctions[prop];
return obj[prop];
}
obj.watch(prop,function(myProp,oldVal,newVal) {
if (newVal !== undefined) {
return ready(newVal);
}
});
};
/* Example pseudo-code: */
when(listbox.venues,'ready',function() { listbox.exhibitions.updateLabels(); });
The big problem with this implementation is that it can’t return a value unless the prop you’re waiting for is already set when you call when(). But I’m fairly proud of it. It has a nice natural calling syntax and gets a lot of stuff done in not much code.
Filed under: Javascript, XUL | 3 Comments
Search
-
You are currently browsing the Pausebuttonedit weblog archives.
Does this work across all browsers? If so, that is amazing. I had no idea you could do that in JavaScript.
I just checked, it doesn’t work in IE.
Yep, it’s geared towards the Mozilla platform — the wonderful thing about developing in XUL is that you get access to the best Javascript implementation in any browser and you don’t need to worry what IE doesn’t support. The Firefox 2.* supports Javascript to v1.7, giving you iterators, generators, array comprehensions and lispy array methods; the betas of Firefox 3.* support Javascript 1.8. See http://developer.mozilla.org/en/docs/JavaScript.