ThomasBurleson
11/15/2011 - 9:30 PM

Use of Deferreds and Promises with Adventure.js for HTML5 Video Popcorn.js SDK

Use of Deferreds and Promises with Adventure.js for HTML5 Video Popcorn.js SDK

/**
 * Below is excerpted code that was improved to properly use Deferreds, construction, and $.when()
 * 
 * @see https://github.com/rwldrn/adventure/blob/master/src/adventure.js
 **/

    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
      loadQueue = [
                    // Load the video will resolve when video is playable
                    $.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(),
                    
                    // when events have been loaded in from the specified file
                    $.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.apply( null, loadQueue )
       .done( 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
          },
          queue = [ ];

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

            queue.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, queue )
         .then( function() {
            // Setup is complete
            console.log( "Ready for assertion tests" );

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