Mobile Zone is brought to you in partnership with:

Troy Miles is a Southern California based software developer. He began by writing games for the Apple II, C64 and IBM PC in assembly language over 30 years ago. After burning out on games he switch to creating windows application software in C and C++. And now he develops applications for both web, mobile web and mobile devices in C#, Objective C, Java, and JavaScript. He is also a big fan of jQuery, jQuery Mobile and PhoneGap. Troy is a DZone MVB and is not an employee of DZone and has posted 25 posts at DZone. You can read more from them at their website. View Full User Profile

jQuery Deferred Object: Your New Best Friend

11.08.2013
| 4829 views |
  • submit to reddit

Here's your scenario: you are creating the splash page for an HTML5 mobile game. While you are loading resources, you display a wait spinner and a text message. This all works well except for when people have really fast internet connections - they don't have enough time to see the splash page or read the message. What you'd like to do is set a minimum amount of time for the message to show, say three seconds. But you aren't looking forward to writing a bunch of nested callback code. What should you do? Deferred object.

Deferred objects were introduced in jQuery 1.5. And with them came the end of lots of gnarly callback code - if only people would use them. Here is jQuery's official definition of a Deferred Object:

Description: A constructor function that returns a chainable utility object with methods to register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.

This is a quick post, so I won't fully explain Deferred Objects now. Instead I will show how to use them to solve the posed scenario. We will use three Deferred Objects. Two of them are passed to us by the Ajax get method, when we start to load our graphic and music resources. The third we will create ourselves for our three second timer. 

Once we have create all of our deferreds, we will display our loading message using jQuery Mobile's loading widget. Then we will use the setTimeout function to give us a three second timer. Once it fires we call the timerReady deferred object's resolve() method. This method does exactly what it name says, it sets the state of the deferred object as resolve.

The next bit of code is the when method. When is used to coordinate more than deferred object. Essentially it says once all of the indicated deferred objects have been resolved, run the code inside of me.

It is important to note that none of this code is synchronous. It is all asynchronous. The when method is like a callback, it gets fired once all of the objects gets resolved, whenever that may be.

For every deferred object in the when statement, you will be passed an array in the done method. This is most relevant with the ajax objects, since the array will contain the results of the ajax calls, but you could also create your own data array for your own deferred objects.
There are also a fail method and an always method. Since the always method is always called, it makes a great to remove the loading widget from the screen. 

Below is the code the for the splash screen complete with deferred objects. The complete code is at: https://github.com/Rockncoder/JQMGame. If you would like a more complete example please follow my plane game repo at: https://github.com/Rockncoder/planegame. There I will build the complete game over the next few months.

  RocknCoder.Pages.splash = (function () {
    return {
      pageshow: function () {
        // create our deferred objects
        // the Ajax get methods return deferred objects
        var timerReady = $.Deferred(),
          spriteMapReady = $.get("1945.png"),
          musicReady = $.get("DST-Afternoon.mp3");

        // put our load screen up
        $.mobile.loading( 'show', {
          text: "Loading resources...",
          textVisible: true,
          theme: "a"
        });

        // our timer simply waits until it times out, then sets timerReady to resolve
        setTimeout(function () {
          timerReady.resolve();
        }, 3000);

        // once all of my deferred objects have resolved, change the page
        $.when(timerReady, spriteMapReady, musicReady)
          .done(function (timerResponse, spriteMapResponse, musicResponse) {
            // let's put the data in our global
            RocknCoder.Resources = RocknCoder.Resources || {};
            RocknCoder.Resources.spriteMap = spriteMapResponse[0];
            RocknCoder.Resources.music = musicResponse[0];
          })
          // here you would check to find out what failed
          .fail(function () {
            console.log("An ERROR Occurred")
          })
          // the always method runs whether or not there were errors
          .always(function() {
            $.mobile.loading( "hide" );
            $.mobile.changePage("#attract");
          });
      },
      pagehide: function () {
      }
    };
  }());


Published at DZone with permission of Troy Miles, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)