In my daily Javascript travails, I frequently need to initialize an object asynchronously. But if it’s asynchronous, I can’t call some of its methods right away! Backbone and jQuery help with this problem by letting you assign events and custom triggers.
With Backbone, you could do something like myObject.on(“ready”, function(){ … }), then call myObject.trigger(“ready”) somewhere else. But that doesn’t cover my use case. If I call myObject.on(“ready”, …) after the ready trigger, then nothing will happen. I’d prefer if it fired right away!
I made my life a lot easier by making a mixin to handle this. You can check it out on github. I wrote it in coffeescript, but included the javascript in case you don’t want to compile.
Here’s a mock of how I might use it with Backbone:
Video = Backbone.Model.extend({
ready: readyMixin,
// this initializer isn't ready until later
initialize: function() {
somethingAsync(function() {
this.videoElt = document.getElementById("my_html5_video");
this.ready(true);
}, this);
},
// internally use ready() so that play() can be called before
// the video is actually ready.
play: function() {
this.ready(function() { this.videoElt.play() });
return this;
}
});
myVideo = new Video().play();
It handles nested ready() calls just fine, and also lets you pass in arguments after the callback. You can sugar up your syntax too by passing the function name as a string.
// This works just fine.
myVideo.ready(function() {
this.ready(function() {
this.play();
}
});
// Passing arguments.
myVideo.ready(function(pauseOptions) { this.pause(pauseOptions) }, options.forPause);
// Sweet sugary goodness, doing the same thing as above
myVideo.ready("pause", options.forPause);
// I could've also done this:
myVideo.ready(this.pause, options.forPause);



