rwldrn/adventure — Issue #1: Improved use of Deferred(s) in adventure.js
Author: ThomasBurleson
Created: 2011-11-15 21:17:08+00:00
State: open

$.Deferred(function(dfd){ /* your use of the deferred instance here... */ }).promise() is the best way to construct a deferred and return a read-only promise. I modified your code to use this approach.

Those changes (shown below) lead to (IMHO) better code clarity and better encapsulation:

init: function( options ) {
// Program references
var

// Shorthand pointer back to Adventure object.
self = Adventure,

// Initialize a popcorn instance by passing the
// specified media element's ID to Popcorn()
self.pop = Popcorn( options.mediaId );

// Localize the options.scenarios data property
self.scenarios = options.scenarios;

// Create two promises
deferred = {
// One for the video;
// will resolve when video is playable
media: $.Deferred(function(dfd){

// Listen for the custom "canplayall" event hook
// to be triggered. Similar to "canplaythrough",
// the "canplayall" event fires when the video fires
// "canplaythrough" for the _first_ _time_ _only_
self.pop.listen( "canplayall", function() {
dfd.resolve( self.pop );
});

}).promise(),
// One for the events;
// will resolve when events have been loaded in
// from the specified file
events: $.Deferred(function(dfd){
// Make a request for the track event data in the
// specified file stored on the server
$.getJSON( options.events, function( data ) {
dfd.resolve( data );
});

}).promise()
};

// When both deferred objects have been resolved,
// proceed to setting up the video's track events,
// and cues
$.when( deferred.media, deferred.events )
.then(function( media, events ) {
console.log( "Continue to movie setup", media, events );

var
// Map an object of data properties to setup tasks
// Create new setup completion deferreds for each
datas = {
cues : options.cues || {},
tracks : events || [],
handlers: options.handlers
},
deferreds = [ ];

// Iterate setup tasks and call each with correlated data
_.forEach( self.setup, function( fn, key ) {

deferreds.push( $.Deferred(function(dfd){
// Call setup function
// Set context to Popcorn instance
// Pass correlated data as argument
fn.call( media, datas[ key ], dfd, self );

// If the expected setup data is actually empty,
// we can premptively resolve the setup completion deferred
if ( _.size( data ) === 0 ) {
dfd.resolve();
}
}).promise());
});

// When all setup deferreds are resolved,
// Setup is complete, can run tests or play game
$.when.apply( null, deferreds ).then(function() {
// Setup is complete
console.log( "Ready for assertion tests" );

self.pop.play();
deferreds = [ ];
});
});
}