On Github patrickberkeley / better-callbacks
It all starts with an innocent little ajax request:
var data; $.get('api/data', function(resp) { data = resp.data; }); doSomethingFancyWithData(data);
// Demonstrates nesting, CPS, 'callback hell' // $.get('api1/data', function(resp1) { // Next that depended on the first response. $.get('api2/data', function(resp2) { // Next request that depended on the second response. $.get('api3/data', function(resp3) { // Next request that depended on the third response. $.get(); // ... you get the idea. }); }); });
$.get('api1/data', function(resp1) { trackMe(); }); $.get('api2/data', function(resp2) { trackMe(); }); $.get('api3/data', function(resp3) { trackMe(); }); var trackedCount = 0; function trackMe() { ++trackedCount; if (trackedCount === 3) { doSomethingThatNeededAllThree(); } }
// The deferred object itself. var def = $.Deferred;
// And the deferred's promise object. def.promise();
def; > { always: function() {}, done: function() {}, fail: function() {}, notify: function() {}, notifyWith: function() {}, pipe: function() {}, progress: function() {}, promise: function() {}, reject: function() {}, rejectWith: function() {}, resolve: function() {}, resolveWith: function() {}, state: function() {}, then: function() {} }
// A read-only version of the deferred object; // returned from a jQuery $.ajax() call. def.promise(); > { always: function() {}, done: function() {}, fail: function() {}, pipe: function() {}, progress: function() {}, promise: function() {}, state: function() {}, then: function() {} }
var deferred = $.Deferred(); deferred.promise().state(); > "pending" deferred.resolve(); deferred.promise().state(); > "resolved"
var deferred = $.Deferred(); deferred.promise().state(); > "pending" deferred.reject(); deferred.promise().state(); > "rejected"
var deferred = $.Deferred(); deferred.pipe( function(resp) { console.log("I filter done responses", resp); }, function(resp) { console.log("I filter fail responses", resp); }, function(resp) { console.log("I filter progress responses", resp); } );
var deferred = $.Deferred(); deferred.resolve(); deferred.done(function() { console.log("I get called when things go well."); });
var deferred = $.Deferred(); deferred.reject(); deferred.fail(function() { console.log("I get called when things fall apart."); });
var deferred = $.Deferred(); deferred.resolve(); deferred.always(function() { console.log("I'm so popular, I get called no matter what."); });
var deferred = $.Deferred(); // Shorthand for done, fail, and always. deferred.then( function(resp) { console.log("I'm a done callback!", resp); }, function(resp) { console.log("I'm a fail callback.", resp); }, function(resp) { console.log("I'm an always callback.", resp); } );
$.get('api1/data', function(resp1) { // Next that depended on the first response. $.get('api2/data', function(resp2) { // Next request that depended on the second response. $.get('api3/data', function(resp3) { // Next request that depended on the third response. }); }); });
var req1 = $.get('api1/data'); var req2 = $.get('api2/data'); var req3 = $.get('api3/data'); req1.then(function(req1Data) { return req2; }).then(function(req2Data) { return req3; }); req2.then(function(req2Data) { // Do something somewhere entirely different. });
$.get('api1/data', function(resp1) { trackMe(); }); $.get('api2/data', function(resp2) { trackMe(); }); $.get('api3/data', function(resp3) { trackMe(); }); var trackedCount = 0; function trackMe() { ++trackedCount; if (trackedCount === 3) { doSomethingThatNeededAllThree(); } }
$.when( $.get('api1/data'), $.get('api2/data'), $.get('api3/data'), { key: 'value' } ).done();
var getArticleByHeadline = function(query) { return $.ajax({ url: 'api/articles' }) .pipe(function(data) { // Filter article headlines by query. }); } getArticleByHeadline('wins election').done(function(articles) { // Do with the articles. });
function showSpinner(){ var deferred = $.Deferred(); $('#spinner').fadeIn(1000, deferred.resolve()); return deferred.promise(); } function disableInputs(){ /* Disable form, return promise */ } function postData(){ return $.post('api/'); } $.when(showSpinner, disableInputs, postData, {random: 'obj'}) .done(function() { /* Clear form */ }) .fail(function() { /* Don't clear form, show error */ }) .always(function() { /* Hide spinner, re-enable form */ });