Skip to content

Instantly share code, notes, and snippets.

@hanleybrand
Created November 27, 2012 17:01
Show Gist options
  • Save hanleybrand/4155503 to your computer and use it in GitHub Desktop.
Save hanleybrand/4155503 to your computer and use it in GitHub Desktop.

jQuery Deferred

Escaping from callback Hell

jQuery.Deferred implements CommonJS Promises/A

It's a chainable utility object that can register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.

##jQuery.Deferred Basics

var deferred = new $.Deferred();

  • done() - Adds a callback to the "done" queue.

  • fail() - Adds a callback to the "fail" queue.

  • resolve() - Executes all queued "done" callbacks with provided arguments.

  • reject() - Executes all queued "fail" callbacks with provided arguments.

    var deferred = new $.Deferred();

    deferred.done(function(message) { alert(message); });

    deferred.resolve("Hello World!");

    deferred.done(function(message) {   also_gets_hello_world(message); }); // deferreds are immutable


jQuery ajax functions return XHR objects that act like deferred.

$.ajax("somefile", {
    success: render,
    error: errorMessage
});

Is equivalent to:

$.ajax("somefile")
    .done(render)
    .fail(errorMessage);
        

            Decoupling Multiple callbacks.

$.ajax("somefile", function(data) {
save(data);
render(data);
});

var someFile = $.ajax("somefile").done(save);
someFile.done(render);

// if the asynchronous function has already finished then render executes immediately.

How is deferred useful?

  • Decoupling Multiple callbacks.
  • Simplify Multiple Dependencies.
  • No nested callbacks with pipe.
  • Easy to mix with callbacks

##Simplify Multiple Dependencies with $.when

var file, image; $.ajax("file", function(data) { file = data; if (file && image) render([file, image]); });

$.ajax("image", function(data) { image = data; if (file && image) render([file, image]); });

$.when($.ajax("file"), $.ajax( "image")).then(render);

Return deferred from your objects.

function ImagesLoaded() {


  var deferred = $.Deferred();
  loadImages(function() {


    deferred.resolve();


  });
  return deferred;

}

$.when(ImagesLoaded(), $.ajax("menu_data"))
  .then(drawMenu);

Using callbacks without deferred.


        
    


    
        
$.ajax("me/friends", function(friends)
{
  getMovies(friends, function(movies) {


    getTitles(movies, alert);
  });
});


        
    




    
        
No nested callbacks with Deferred.pipe


        
    


    
        


    $.ajax("me/friends")
        
    
      .pipe(getMovies)
      .pipe(getTitles)
      .done(alert);


    

Pipe takes a function that returns a deferred.  By returning a function
    we are allowing for lazy execution.

First the callback way.

function getMovies(friends, callback) {
    var movieCalls = [];
  friends.forEach(function(friend) {
    $.ajax("movies/" +
    friend.id, function(movie) {
      if (movieCalls.length == friends.length) {
    

        callback(Array.concatMultiple(movieCalls));
      }
    });
  });

Deferred, Cheaper than we thought ...

function getMovies() { return $.when($.map(friends, function(friend) {

    return $.ajax("movies/" +
	friend.id);  })).pipe(Array.concatMultiple);

}

Easy to mix with callbacks

function AsyncMessage(msg, delay, callback) { var deferred = new $.Deferred(); deferred.done(callback); setTimeout(function() { deferred.resolve(msg);

}, delay); return deferred; }

AsyncMessage("hi", 10, alert);

AsyncMessage("hi", 10).done(alert);

AsyncMessage("hi", 10, alert).done(alert);

What if we mixed all these together?

Decoupling Multiple callbacks.
Simplify Multiple Dependencies.
No nested callbacks with pipe.
Easy to mix with callbacks (legacy code)


We get loosely coupled code with simplified dependency handling
	and fewer nested callbacks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment