If you prefer CoffeeScript, see README.coffee.md.
Deferrable adds a layer between you're own callbacks and the hooks calling them. You therefore can use a callback waiting for multiple events to finish without nesting callbacks. This has the huge advantage of improving concurrency as events can be processed simultaneously instead of sequentially.
Take this example:
showAnimation(function() {
loadContent(function() {
displayContent();
});
});
In that case the animation is happening totally asynchronously, but we don't take advantage of that. We only start loading content when the animation has finished.
Or would it be smart to load the content first?
loadContent(function() {
showAnimation(function() {
displayContent();
});
});
In that case some time would go by without any visible feedback for the user. Sure, the content comes right in after playing the animation. But what we really want it to load the content while playing the animation. However, we need both the content to have arrived and the animation to be done before we can display the new content:
var d;
d = new Deferrable();
loadContent(d.callback());
showAnimation(d.callback());
d.onSuccess(function() {
displayContent();
});
It does not matter which event finishes first and whether that happens before or after calling onSuccess
.
If both events finish, the onSuccess
callback will be called exactly once.
This works with as many events as you like.
Take this code example:
var deferrable, reusable;
deferrable = new Deferrable();
reusable = deferrable.callback();
first(deferrable.callback());
second(reusable);
third(reusable);
deferrable.onSuccess(function() {
something();
});
In that example something
will be called as soon as the event first
and either second
or third
have
finished.
It is also possible to have Deferrable depending on each other:
var a, b, c;
a = new Deferrable();
b = new Deferrable();
c = new Deferrable();
document.onload = a.callback();
a.onSuccess(b.callback());
b.onSuccess(c.callback());
You probably want to access the arguments passed on by the events. If we take the first example: loadContent
is probably handing over the body and header of an AJAX response. In order to do so, we have to name the callbacks:
var deferrable;
deferrable = new Deferrable();
loadContent(deferrable.callback('content'));
showAnimation(deferrable.callback());
deferrable.onSuccess(function(results) {
var body, header;
body = results.content[0];
header = results.content[1];
displayContent(body);
});
Download the source from here or install via npm: npm install deferrable
.
Store deferrable.js somewhere and load
into in your page by using <script src='deferrable.js'></script>
.
On Node.js and any other implementation allows replacing exports
, you can simply do:
var Deferrable;
Deferrable = require('deferrable');
If your platform does not support replacing exports
, you can always use this:
var Deferrable;
Deferrable = require('deferrable').Deferrable;
run rake build
and open test/deferrable_test.html
.
run rake test
.
run rake build
and open test/deferrable_test.js
Supported platforms:
- Any common web browser with js support (Netscape 4.0 or later, Internet Explorer 5.5 or later, Opera 5.12 or later, Firefox 1.0 or later, Konqueror 3.1 or later, Safari, Chrome, ...)
- Any CommonJS implementation supporting Modules 1.x (CoucheDB 0.11 or later, Ejscript 2.0 or later, Flusspferd, GPSEE, Narwhal 0.1 or later, Perserve, RingoJS, Smart Platform, SproutCore 1.1 or later, Wakanda, Yabble, node.js, v8cgi)