DEFERREDS
Putting Laziness to Work
Dan Heberden
danheberden.com
@danheberden
danheberden.com
@danheberden
Use left and right arrow keys to navigate slides
this only runs/works right in chrome
this only runs/works right in chrome
$.ajax({
url: "server/get-data/",
success: function( data ) {
callMeBack( data );
}
});
function goGetIt() {
var whatGotReturned;
$.ajax({
url: "server/get-data/",
success: function( data ) {
whatGotReturned = data;
}
});
return whatGotReturned;
}
goGetIt(); // returns undefined
function goGetIt( callMeBack ) {
$.ajax({
url: "server/get-data/",
success: function( data ) {
callMeBack( data );
}
});
}
goGetIt( function( data ) {
// handle data
});
Accepts any number of functions to call when resolved
Accepts any humber of functions to call when rejected
Convenience method that takes one done and one fail callback
Determine if the deferred has been rejected
The 'With' variants accept a context as the first arg
Determine if the deferred has been resolved
more on this later :)
// create a new deferred
var dfd = $.Deferred();
dfd.done( function( data ) {
output( 'done!' + data );
});
dfd.resolve( 'yay!' );
// create a new deferred
var dfd = $.Deferred();
dfd.fail( function( data ) {
output( 'broked!' + data );
});
dfd.reject( 'oh noes!' );
function doSomethingAsynchronous() {
var dfd = $.Deferred();
setTimeout( function() {
dfd.resolve( 'did it!' )
}, 4000 );
return dfd.promise();
}
doSomethingAsynchronous()
.done( function( data ) {
output( 'we '+ data );
});
Accepts any number of functions to call when resolved
Accepts any humber of functions to call when rejected
Convenience method that takes one done and one fail callback
Determine if the deferred has been rejected
Determine if the deferred has been resolved
Another promise
var didIt = function() {
output( 'did it!' );
},
failed = function() {
output( 'failed!' );
}
doSomethingAsynchronous()
.then( didIt, failed )
.done( didIt )
.fail( failed );
Requires a new deffered be returned to be able to call .then again
You can look it up if you wanna, but trust me: we did a good job
If a deferred has already been resolved, and you attach a function to .done ( or similarly with rejected and .fail ) the function you attach will be called immediately (since it's already been resolved )
We can create a deferred object that holds our callbacks
We can return, pass around, store, etc a public interface for the deferred: a promise
We can easily resolve or reject that deferred
Resolved or rejected data is passed to the callbacks no matter where they were assigned
$.ajax({
url: 'srv/echo',
data: { echo: "stuff",
delay: 1,
error: 1}
}).done(
function( data, status, jqXHR ) {
output( data );
}
);
Works just like .done
Works just like .fail
Is called when complete but 1st param is the jqXHR
$.ajax({
url: '/srv/echo',
data: { echo: "stuff" },
success: function( data ) {
output( data );
}
});
function getUserName() {
return $.ajax({
url: 'srv/echo',
data: { random: 1 }
});
}
getUserName().done( function( name ) {
output( name );
});
function aName() {
return $.get( 'srv/echo', { random:1 });
}
$.when( aName(), "JQ", aName(), { a: "eh?" } )
.done( function( a1, txt, a2, obj ) {
output( a1[ 0 ] );
output( txt );
output( a2[ 0 ] );
output( obj );
});
function aName() {
return $.get( 'srv/echo', { random:1 });
}
function customDfd() {
var dfd = $.Deferred();
setTimeout( function() {
dfd.resolve( 'all done!' );
}, 4000 );
return dfd.promise();
}
$.when( aName(), customDfd() )
.done( function( name, custom ) {
output( name[ 0 ] );
});
var getName = (function() {
var cache; // private cache
// gets assigned to getName
return function() {
// return the cache if it's valid or
return cache || $.ajax({
url: 'srv/echo',
data: { random: 1 },
success: function( data ) {
cache = data;
}
});
};
})();
var getName = (function() {
var cache = false; // private cache
// gets assigned to getName
return function() {
// return the cache if it's valid or
return cache ? cache : $.ajax({
url: 'srv/echo',
data: { random: 1 },
success: function( data ) {
cache = data;
}
}) ;
};
})();
$.when( getName() ).done(
function( name ) {
output( name );
$.when( getName() ).done(
function( name ) {
output( name );
});
});
$( 'div.someClass' ).animate( {
left: "+=100"
}, {
duration:1000,
complete: function() {
// gets called every time
}
});
$( '#bounceDemo div' ).animate({
bottom: "0"
},{
duration: 1700,
easing: "easeOutBounce"
}).promise()
.done( function() {
output('all done');
});
$( '#bounceDemo div' ).each( function() {
$(this).css('bottom', ~~(Math.random() * 5) + 4 + "em" );
});
$.when(
$( '#bounceDemo2 div' ).animate({
bottom: "0"
},{
duration: 1700,
easing: "easeOutBounce"
})
).done( function() {
output('all done');
});
$( '#bounceDemo2 div' ).each( function() {
$(this).css('bottom', ~~(Math.random() * 5) + 4 + "em" );
});
$.fn.drop = function( dur ) {
return this.animate({
bottom: 0
}, {
duration: dur || 1700,
easing: "easeOutBounce"
});
}
var $balls = $( '#bounceDemo3 div' ),
a = $balls.eq(0).drop( 500 ),
b = $balls.eq(1).drop( 2000 ),
c = $balls.eq(2).drop( 4000 );
$.when( a, b, c )
.done( function() {
output( 'lol the balls dropped' );
});
$( '#bounceDemo3 div' ).each( function() {
$(this).css('bottom', ~~(Math.random() * 5) + 4 + "em" );
});
var $balls = $( '#bounceDemo4 div' ),
$a = $balls.eq(0).drop( 500 ),
$b = $balls.eq(1).drop( 2000 ),
$c = $balls.eq(2).drop( 4000 );
setTimeout( function() {
$c.stop();
},1000 );
$.when( $a, $b, $c )
.done( function() {
output( 'lol the balls dropped' );
});
$( '#bounceDemo4 div' ).each( function() {
$(this).css('bottom', ~~(Math.random() * 5) + 4 + "em" );
});
var $balls = $( '#bounceDemo4 div' ),
$a = $balls.eq(0).drop( 500 ),
$b = $balls.eq(1).drop( 2000 ),
$c = $balls.eq(2).drop( 4000 );
$.when( $a, $b, $c )
.done( function( a, b, c ) {
// a is $a
// b is $b
// c is $c
});
function aName( delay ) {
return $.get( 'srv/echo', { random:1 });
}
var $balls = $( '#bounceDemo6 div' ),
$a = $balls.eq(0).drop( 500 ),
$b = $balls.eq(1).drop( 2000 ),
$c = $balls.eq(2).drop( 4000 ),
$name = $.get( 'srv/echo', {
random:1,
delay: 5 });
$.when( $a, $b, $c, $name )
.done( function( a, b, c, nameReq ) {
output( nameReq[ 0 ] );
});
$( '#bounceDemo6 div' ).each( function() {
$(this).css('bottom', ~~(Math.random() * 5) + 4 + "em" );
});
var $balls = $( '#bounceDemo7 div' );
$.when( $balls.fadeOut( 2000 ) )
.done( function() {
output( 'done fading out' );
});
$( '#bounceDemo7 div' ).each( function() {
$(this).fadeIn(0);
});
Wanna run the same function regardless if the deferred was resolved or rejected?
var allDone = function() {}
.always( allDone );
// is the same as
.then( allDone, allDone );
var promise = $.ajax({
url: 'srv/echo',
data: { echo: "jQuery" }
})
.pipe( function( data ) {
// return a new promise that gets piped
return $.ajax({
url: 'srv/echo',
data: { echo: data + data + data}
});
});
$.when( promise ).done( function( data ){
output( data );
});
function getUser( userID ) {
return $.get( 'srv/test/user' , {
id: userID
});
}
$.when( getUser(3) )
.done( function( data ) {
output( data );
});
function getUser( userID ) {
return { name: "Joe", email: "joe@nowhere.com"}
}
$.when( getUser(3) )
.done( function( data ) {
output( data );
});
(function() {
var cache = {};
app.getTemplate = function( tmpl ) {
return cache[ tmpl ] || $.ajax({
url: '/go/get/template/',
data: { template: tmpl },
success: function( data ) {
cache[ tmpl ] = data;
}
});
}
})();
(function() {
app.getUserData = function( uID ) {
return $.ajax({
url: '/go/get/user/',
data: { id: uID }
});
}
})();
$.when( app.getTmpl( 'usrEdit' ),
app.getUserData( 14 ) )
.done( function( tmplData, user ){
// render the template with
// the template and data
$( tmplData ).tmpl( user )
.appendTo( '#userDisplay' );
});
$.when( "talk" )
.done( function() {
output( "questions?" );
})