Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

add deferreds content #156

Merged
merged 1 commit into from

5 participants

John K. Paul adam j. sontag Addy Osmani Rebecca Murphey Bob Holt
John K. Paul
Collaborator

No description provided.

John K. Paul
Collaborator

This fixes issue #3

page/code-organization/deferreds.md
@@ -0,0 +1,676 @@
+---
+title: Deferreds
+level: advanced
+source: http://msdn.microsoft.com/en-us/magazine/gg723713.aspx
+attribution:
+ - Julian Aubourg <j@ubourg.net>
+ - Andree Hansson <peolanha@gmail.com>
adam j. sontag Collaborator
ajpiano added a note

should add @addyosmani here, he and @jaubourg did the original content, @peolanha helped with converting it to markdown!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
page/code-organization/deferreds.md
((5 lines not shown))
+attribution:
+ - Julian Aubourg <j@ubourg.net>
+ - Andree Hansson <peolanha@gmail.com>
+---
+
+At a high-level, deferreds can be thought of as a way to represent
+costly operations which can take a long time to complete. They&apos;re the
+asynchronous alternative to blocking functions and the general idea is
+that rather than your application blocking while it awaits some request
+to complete before returning a result, a deferred object can instead be
+returned immediately. You can then attach callbacks to the deferred
+object: they will be called once the request has actually completed.
+
+##Promises
+
+In its most basic form, a &apos;promise&apos; is a model that provides a solution
adam j. sontag Collaborator
ajpiano added a note

why is there &apos here twice?

Rebecca Murphey Collaborator

I think just use normal punctuation here and it will get made pretty by the markdown converter as appropriate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
page/code-organization/deferreds.md
((77 lines not shown))
+
+```
+when(
+ promise1,
+ promise2,
+ ...
+).then(function( futureValue1, futureValue2, ... ) {
+ /* all promises have completed and are resolved */
+});
+```
+
+A good example is a scenario where you may have multiple concurrent
+animations that are being run. Without keeping track of each callback
+firing on completion, it can be difficult to truly establish once all
+your animations have finished running. Using promises and 'when' however
+this is very straight-forward as each of your animations can effectively
adam j. sontag Collaborator
ajpiano added a note

straightforward is one word

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
page/code-organization/deferreds.md
((109 lines not shown))
+This means that one can basically write non-blocking logic that can be
+executed without synchronization. Rather than directly passing callbacks
+to functions, something which can lead to tightly coupled interfaces,
+using promises allows one to separate concerns for code that is
+synchronous or asynchronous.
+
+##jQuery Deferreds
+
+jQuery's implementation of deferreds, first introduced in jQuery 1.5,
+offers a solution which doesn't hugely differ from the section above
+describing the high-level concept of promises - in principle, you are
+given the ability to 'defer' the return of a result to some point in the
+future, which wasn't previously possible using the library alone.
+
+Deferreds were added as a part of a large rewrite of the ajax module,
+led by Julian following the CommonJS Promises/A design. Whilst 1.5 and
adam j. sontag Collaborator
ajpiano added a note

add "Aubourg"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
page/code-organization/deferreds.md
((655 lines not shown))
+ element.attr( "src", src );
+ }, function() {
+ element.attr( "src", "error.png" );
+ } ).done(function() {
+ element.fadeIn();
+ });
+ } );
+ }
+});
+```
+
+Here, we first wait for the delay to be fulfilled before attempting to
+load the image. It can make a lot of sense when you want to limit the
+number or network requests on page load.
+
+##Conclusions
adam j. sontag Collaborator
ajpiano added a note

I don't think we need this entire paragraph at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
page/code-organization/deferreds.md
((102 lines not shown))
+ promise2
+).then(function(){
+ /* once both animations have completed
+ we can then run our additional logic */
+});
+```
+
+This means that one can basically write non-blocking logic that can be
+executed without synchronization. Rather than directly passing callbacks
+to functions, something which can lead to tightly coupled interfaces,
+using promises allows one to separate concerns for code that is
+synchronous or asynchronous.
+
+##jQuery Deferreds
+
+jQuery's implementation of deferreds, first introduced in jQuery 1.5,
adam j. sontag Collaborator
ajpiano added a note

Change this to from "jQuery's implementation of deferreds, ... , offers" to "jQuery's deferreds, ... , offer"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
adam j. sontag
Collaborator

All the &apos; need to be fixed

In general, I can't help the feeling this should be broken into smaller bits - at the very least, separating out the "further examples" section into its own article. Thoughts?

page/code-organization/deferreds.md
((84 lines not shown))
+ /* all promises have completed and are resolved */
+});
+```
+
+A good example is a scenario where you may have multiple concurrent
+animations that are being run. Without keeping track of each callback
+firing on completion, it can be difficult to truly establish once all
+your animations have finished running. Using promises and 'when' however
+this is very straight-forward as each of your animations can effectively
+say &apos;we promise to let you know once we're done&apos;. The compounded result
+of this means it's a trivial process to execute a single callback once
+the animations are done. For example:
+
+```
+var promise1 = $('#id1').animate().promise();
+var promise2 = $('#id2').animate().promise();
Bob Holt Collaborator
bobholt added a note

double quotes here, please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
John K. Paul
Collaborator

@ajpiano I agree on separating this out into multiple articles, There is a lot more than should be in the single article about deferreds. I will look into this and the other notes this weekend.

page/code-organization/deferreds.md
@@ -0,0 +1,676 @@
+---
+title: Deferreds
+level: advanced
+source: http://msdn.microsoft.com/en-us/magazine/gg723713.aspx
+attribution:
+ - Julian Aubourg <j@ubourg.net>
+ - Andree Hansson <peolanha@gmail.com>
+---
+
+At a high-level, deferreds can be thought of as a way to represent
+costly operations which can take a long time to complete. They&apos;re the
Rebecca Murphey Collaborator

I wouldn't necessarily agree about the "costly" part -- it's really just about async operations generally, which aren't necessarily costly, just non-blocking .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
page/code-organization/deferreds.md
((7 lines not shown))
+ - Andree Hansson <peolanha@gmail.com>
+---
+
+At a high-level, deferreds can be thought of as a way to represent
+costly operations which can take a long time to complete. They&apos;re the
+asynchronous alternative to blocking functions and the general idea is
+that rather than your application blocking while it awaits some request
+to complete before returning a result, a deferred object can instead be
+returned immediately. You can then attach callbacks to the deferred
+object: they will be called once the request has actually completed.
+
+##Promises
+
+In its most basic form, a &apos;promise&apos; is a model that provides a solution
+for the concept of deferred (or future) results in software engineering.
+The main idea behind it is something we&apos;ve already covered: rather than
Rebecca Murphey Collaborator

Two things:

  • avoid "we", per the style guide
  • since these articles may be consumed out of sequence, "already covered" isn't necessarily accurate -- better to link to another resource where the concept you're referring to is covered
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
John K. Paul
Collaborator

I've addressed all of the notes in this PR. I've rewritten the portions with 'we' and split this out into three separate articles.

Addy Osmani
Collaborator

Nice work @johnkpaul :) The separation into three distinct pieces appears to have been done quite cleanly and this looks good for a merge to me.

Addy Osmani addyosmani merged commit da12e4d into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 14, 2012
  1. John K. Paul

    add deferreds content

    johnkpaul authored
This page is out of date. Refresh to see the latest.
3  order.yml
View
@@ -92,6 +92,7 @@
- feature-browser-detection
- deferreds:
- about-deferreds
- - something-else
+ - jquery-deferreds
+ - examples
- jquery-mobile:
- getting-started
114 page/code-organization/deferreds.md
View
@@ -0,0 +1,114 @@
+---
+title: Deferreds
+level: advanced
+source: http://msdn.microsoft.com/en-us/magazine/gg723713.aspx
+attribution:
+ - Julian Aubourg <j@ubourg.net>
+ - Addy Osmani <addyosmani@gmail.com>
+ - Andree Hansson <peolanha@gmail.com>
+---
+
+At a high-level, deferreds can be thought of as a way to represent
+asynchronous operations which can take a long time to complete. They're the
+asynchronous alternative to blocking functions and the general idea is
+that rather than your application blocking while it awaits some request
+to complete before returning a result, a deferred object can instead be
+returned immediately. You can then attach callbacks to the deferred
+object: they will be called once the request has actually completed.
+
+##Promises
+
+In its most basic form, a 'promise' is a model that provides a solution
+for the concept of deferred (or future) results in software engineering.
+The main idea behind it is something we've already covered: rather than
+executing a call which may result in blocking, we instead return a
+promise for a future value that will eventually be satisfied.
+
+If it helps to have an example here, consider that you are building a
+web application which heavily relies on data from a third party API. A
+common problem that's faced is having an unknown knowledge of the API
+server's latency at a given time so it's possible that other parts of
+your application may be blocked from running until a result from it is
+returned. Deferreds provide a better solution to this problem, one which
+is void of 'blocking' effects and completely decoupled.
+
+The [Promise/A](http://wiki.commonjs.org/wiki/Promises/A) proposal
+defines a method called 'then' that can be used to register callbacks to
+a promise and, thus, get the future result when it is available. The
+pseudo-code for dealing with a third party API that returns a promise
+may look like:
+
+```
+promise = callToAPI( arg1, arg2, ...);
+
+promise.then(function( futureValue ) {
+ /* handle futureValue */
+});
+
+promise.then(function( futureValue ) {
+ /* do something else */
+});
+```
+
+Furthermore, a promise can actually end up being in two different
+states:
+
+- resolved: in which case data is available
+- rejected: in which case something went wrong and no value is
+ available
+
+Thankfully, the 'then' method accepts two parameters: one for when the
+promise was resolved, another for when the promise was rejected. If we
+get back to pseudo-code, we may do things like:
+
+```
+promise.then( function( futureValue ) {
+ /* we got a value */
+} , function() {
+ /* something went wrong */
+} );
+```
+
+In the case of certain applications, it is necessary to have several
+results returned before your application can continue at all (for
+example, displaying a dynamic set of options on a screen before a user
+is able to select the option that interests them).Where this is the
+case, a method called 'when' exists, which can be used to perform some
+action once all the promises have been fully fulfilled:
+
+```
+when(
+ promise1,
+ promise2,
+ ...
+).then(function( futureValue1, futureValue2, ... ) {
+ /* all promises have completed and are resolved */
+});
+```
+
+A good example is a scenario where you may have multiple concurrent
+animations that are being run. Without keeping track of each callback
+firing on completion, it can be difficult to truly establish once all
+your animations have finished running. Using promises and 'when' however
+this is very straightforward as each of your animations can effectively
+say 'we promise to let you know once we're done'. The compounded result
+of this means it's a trivial process to execute a single callback once
+the animations are done. For example:
+
+```
+var promise1 = $("#id1").animate().promise();
+var promise2 = $("#id2").animate().promise();
+when(
+ promise1,
+ promise2
+).then(function(){
+ /* once both animations have completed
+ we can then run our additional logic */
+});
+```
+
+This means that one can basically write non-blocking logic that can be
+executed without synchronization. Rather than directly passing callbacks
+to functions, something which can lead to tightly coupled interfaces,
+using promises allows one to separate concerns for code that is
+synchronous or asynchronous.
427 page/code-organization/deferreds/examples.md
View
@@ -0,0 +1,427 @@
+---
+title: Deferreds
+level: advanced
+source: http://msdn.microsoft.com/en-us/magazine/gg723713.aspx
+attribution:
+ - Julian Aubourg <j@ubourg.net>
+ - Addy Osmani <addyosmani@gmail.com>
+ - Andree Hansson <peolanha@gmail.com>
+---
+
+##Further Deferreds examples
+
+Deferreds are used behind the hood in Ajax but it doesn't mean they can't also
+be used elsewhere. This section describes situations where deferreds will help
+abstract away asynchronous behaviour and decouple our code.
+
+### Caching
+
+#### Asynchronous cache
+
+When it comes to asynchronous tasks, caching can be a bit demanding
+since you have to make sure a task is only performed once for a given
+key. As a consequence, the code has to somehow keep track of inbound
+tasks.
+
+```
+$.cachedGetScript( url, callback1 );
+$.cachedGetScript( url, callback2 );
+```
+
+The caching mechanism has to make sure the url is only requested once
+even if the script isn't in cache yet. This shows some logic
+to keep track of callbacks bound to a given url in order for the cache
+system to properly handle both complete and inbound requests.
+
+```
+var cachedScriptPromises = {};
+
+$.cachedGetScript = function( url, callback ) {
+ if ( !cachedScriptPromises[ url ] ) {
+ cachedScriptPromises[ url ] = $.Deferred(function( defer ) {
+ $.getScript( url ).then( defer.resolve, defer.reject );
+ }).promise();
+ }
+ return cachedScriptPromises[ url ].done( callback );
+};
+```
+
+One promise is cached per url. If there is no promise for the given url yet,
+then a deferred is created and the request is issued. If it already exists, however,
+the callback is attached to the existing deferred. The big advantage of this
+solution is that it will handle both complete and inbound requests
+transparently. Another advantage is that a deferred-based cache will deal with
+failure gracefully. The promise will end up rejected which can be tested for by
+providing an error callback:
+
+```
+$.cachedGetScript( url ).then( successCallback, errorCallback );
+```
+
+#### Generic asynchronous cache
+
+It is also possible to make the code completely generic and build a
+cache factory that will abstract out the actual task to be performed
+when a key isn't in the cache yet:
+
+```
+$.createCache = function( requestFunction ) {
+ var cache = {};
+ return function( key, callback ) {
+ if ( !cache[ key ] ) {
+ cache[ key ] = $.Deferred(function( defer ) {
+ requestFunction( defer, key );
+ }).promise();
+ }
+ return cache[ key ].done( callback );
+ };
+}
+```
+
+Now that the request logic is abstracted away, cachedGetScript can be rewritten
+as follows:
+
+```
+$.cachedGetScript = $.createCache(function( defer, url ) {
+ $.getScript( url ).then( defer.resolve, defer.reject );
+});
+```
+
+This will work because every call to createCache will create a new cache
+repository and return a new cache-retrieval function.
+
+#### Image loading
+
+A cache can be used to ensure that the same image is not loaded multiple times.
+
+```
+$.loadImage = $.createCache(function( defer, url ) {
+ var image = new Image();
+ function cleanUp() {
+ image.onload = image.onerror = null;
+ }
+ defer.then( cleanUp, cleanUp );
+ image.onload = function() {
+ defer.resolve( url );
+ };
+ image.onerror = defer.reject;
+ image.src = url;
+});
+```
+
+Again, the following snippet:
+
+```
+$.loadImage( "my-image.png" ).done( callback1 );
+$.loadImage( "my-image.png" ).done( callback2 );
+```
+
+will work regardless of whether my-image.png has already been loaded or
+not, or if it is actually in the process of being loaded.
+
+#### Caching Data API responses
+
+API requests that are considered immutable during the lifetime of your
+page are also perfect candidates. For instance, the following:
+
+```
+$.searchTwitter = $.createCache(function( defer, query ) {
+ $.ajax({
+ url: "http://search.twitter.com/search.json",
+ data: {
+ q: query
+ },
+ dataType: "jsonp",
+ success: defer.resolve,
+ error: defer.reject
+ });
+});
+```
+
+will allow you to perform searches on Twitter and cache them at the same
+time:
+
+```
+$.searchTwitter( "jQuery Deferred", callback1 );
+$.searchTwitter( "jQuery Deferred", callback2 );
+```
+
+#### Timing
+
+This deferred-based cache is not limited to network requests; it can
+also be used for timing purposes.
+
+For instance, you may need to perform an action on the page after a
+given amount of time so as to attract the user's attention to a specific
+feature they may not be aware of or deal with a timeout (for a quiz
+question for instance). While setTimeout is good for most use-cases it
+doesn't handle the situation when the timer is asked for later, even
+after it has theoretically expired. We can handle that with the
+following caching system:
+
+```
+var readyTime;
+
+$(function() {
+ readyTime = jQuery.now();
+});
+
+$.afterDOMReady = $.createCache(function( defer, delay ) {
+ delay = delay || 0;
+ $(function() {
+ var delta = $.now() - readyTime;
+ if ( delta >= delay ) {
+ defer.resolve();
+ } else {
+ setTimeout( defer.resolve, delay - delta );
+ }
+ });
+});
+```
+
+The new afterDOMReady helper method provides proper timing after the DOM
+is ready while ensuring the bare minimum of timers will be used. If the
+delay is already expired, any callback will be called right away.
+
+### One-time event
+
+While jQuery offers all the event binding one may need, it can become a
+bit cumbersome to handle events that are only supposed to be dealt with
+once.
+
+For instance, you may wish to have a button that will open a panel the
+first time it is clicked and leave it open afterwards or take special
+initialization actions the first time said button is clicked. When
+dealing with such a situation, one usually end up with code like this:
+
+```
+var buttonClicked = false;
+
+$( "#myButton" ).click(function() {
+ if ( !buttonClicked ) {
+ buttonClicked = true;
+ initializeData();
+ showPanel();
+ }
+});
+```
+
+then, later on, you may wish to take actions, but only if the panel is
+opened:
+
+```
+if ( buttonClicked ) {
+ /* perform specific action */
+}
+```
+
+This is a very coupled solution. If you want to add some other action,
+you have to edit the bind code or just duplicate it all. If you don't,
+your only option is to test for buttonClicked and you may lose that new
+action because the buttonClicked variable may be false and your new code
+may never be executed.
+
+We can do much better using deferreds (for simplification sake, the
+following code will only work for a single element and a single event
+type, but it can be easily generalized for full-fledged collections with
+multiple event types):
+
+```
+$.fn.bindOnce = function( event, callback ) {
+ var element = $( this[ 0 ] ),
+ defer = element.data( "bind_once_defer_" + event );
+ if ( !defer ) {
+ defer = $.Deferred();
+ function deferCallback() {
+ element.unbind( event, deferCallback );
+ defer.resolveWith( this, arguments );
+ }
+ element.bind( event, deferCallback )
+ element.data( "bind_once_defer_" + event , defer );
+ }
+ return defer.done( callback ).promise();
+};
+```
+
+The code works as follows:
+
+- check if the element already has a deferred attached for the given
+ event
+- if not, create it and make it so it is resolved when the event is
+ fired the first time around
+- then attach the given callback to the deferred and return the
+ promise
+
+While the code is definitely more verbose, it makes dealing with the
+problem at hand much simpler in a compartmentalized and decoupled way.
+But let's define a helper method first:
+
+```
+$.fn.firstClick = function( callback ) {
+ return this.bindOnce( "click", callback );
+};
+```
+
+Then the logic can be re-factored as follows:
+
+```
+var openPanel = $( "#myButton" ).firstClick();
+
+openPanel.done( initializeData );
+openPanel.done( showPanel );
+```
+
+If an action should be performed only when a panel is opened later on:
+
+```
+openPanel.done(function() {
+ /* perform specific action */
+});
+```
+
+Nothing is lost if the panel isn't opened yet, the action will just get
+deferred until the button is clicked.
+
+### Combining helpers
+
+All of the samples above can seem a bit limited when looked at
+separately. However, the true power of promises comes into play when you
+mix them together.
+
+#### Requesting panel content on first click and opening said panel
+
+Following is the code for a button that, when clicked, opens a panel.
+It requests its content over the wire and then fades the content in. Using
+the helpers defined earlier, it could be defined as:
+
+```
+$( "#myButton" ).firstClick(function() {
+ var panel = $( "#myPanel" );
+ $.when(
+ $.get( "panel.html" ),
+ panel.slideDownPromise()
+ ).done(function( ajaxResponse ) {
+ panel.html( ajaxResponse[ 0 ] ).fadeIn();
+ });
+});
+```
+
+#### Loading images in a panel on first click and opening said panel
+
+Another possible goal is to have the panel fade in, only after the button
+has been clicked and after all of the images have been loaded.
+
+The html code for this would look something like:
+
+```
+<div id="myPanel">
+ <img data-src="image1.png" />
+ <img data-src="image2.png" />
+ <img data-src="image3.png" />
+ <img data-src="image4.png" />
+</div>
+```
+
+We use the data-src attribute to keep track of the real image location.
+The code to handle our use case using our promise helpers is as follows:
+
+```
+$( "#myButton" ).firstClick(function() {
+
+ var panel = $( "#myPanel" ),
+ promises = [];
+
+ $( "img", panel ).each(function() {
+ var image = $( this ),
+ src = element.attr( "data-src" );
+ if ( src ) {
+ promises.push(
+ $.loadImage( src ).then( function() {
+ image.attr( "src", src );
+ }, function() {
+ image.attr( "src", "error.png" );
+ } )
+ );
+ }
+ });
+
+ promises.push(
+ panel.slideDownPromise()
+ );
+
+ $.when.apply( null, promises ).done(function() {
+ panel.fadeIn();
+ });
+});
+```
+
+The trick here is to keep track of all the loadImage promises. We later
+join them with the panel slideDown animation using $.when. So when the
+button is first clicked, the panel will slideDown and the images will
+start loading. Once the panel has finished sliding down and all the
+images have been loaded, then, and only then, will the panel fade in.
+
+#### Loading images on the page after a specific delay
+
+In order to implement deferred image display on the entire page,
+the following format in HTML can be used.
+
+```
+ <img data-src="image1.png" data-after="1000" src="placeholder.png" />
+ <img data-src="image2.png" data-after="1000" src="placeholder.png" />
+ <img data-src="image1.png" src="placeholder.png" />
+ <img data-src="image2.png" data-after="2000" src="placeholder.png" />
+```
+
+What it says is pretty straight-forward:
+
+- load image1.png and show it immediately for the third image and
+ after one second for the first one
+- load image2.png and show it after one second for the second image
+ and after two seconds for the fourth image
+
+
+```
+$( "img" ).each(function() {
+ var element = $( this ),
+ src = element.attr( "data-src" ),
+ after = element.attr( "data-after" );
+ if ( src ) {
+ $.when(
+ $.loadImage( src ),
+ $.afterDOMReady( after )
+ ).then(function() {
+ element.attr( "src", src );
+ }, function() {
+ element.attr( "src", "error.png" );
+ } ).done(function() {
+ element.fadeIn();
+ });
+ }
+});
+```
+
+In order to delay the loading of the images themselves:
+
+```
+$( "img" ).each(function() {
+ var element = $( this ),
+ src = element.attr( "data-src" ),
+ after = element.attr( "data-after" );
+ if ( src ) {
+ $.afterDOMReady( after, function() {
+ $.loadImage( src ).then(function() {
+ element.attr( "src", src );
+ }, function() {
+ element.attr( "src", "error.png" );
+ } ).done(function() {
+ element.fadeIn();
+ });
+ } );
+ }
+});
+```
+
+Here, after the delay to be fulfilled then the image is loaded. It can make a
+lot of sense when you want to limit the number or network requests on page
+load.
112 page/code-organization/deferreds/jquery-deferreds.md
View
@@ -0,0 +1,112 @@
+---
+title: Deferreds
+level: advanced
+source: http://msdn.microsoft.com/en-us/magazine/gg723713.aspx
+attribution:
+ - Julian Aubourg <j@ubourg.net>
+ - Addy Osmani <addyosmani@gmail.com>
+ - Andree Hansson <peolanha@gmail.com>
+---
+
+##jQuery Deferreds
+
+Deferreds were added as a part of a large rewrite of the ajax module,
+led by Julian Auborg following the CommonJS Promises/A design. Whilst 1.5 and
+above include deferred capabilities, former versions of jQuery had
+jQuery.ajax() accept callbacks that would be invoked upon completion or
+error of the request, but suffered from heavy coupling - the same
+principle that would drive developers using other languages or toolkits
+to opt for deferred execution.
+
+In practice what jQuery's version provides you with are several
+enhancements to the way callbacks are managed, giving you significantly
+more flexible ways to provide callbacks that can be invoked whether the
+original callback dispatch has already fired or not. It is also worth
+noting that jQuery's Deferred object supports having multiple callbacks
+bound to the outcome of particular tasks (and not just one) where the
+task itself can either be synchronous or asynchronous.
+
+At the heart of jQuery's implementation is jQuery.Deferred - a chainable
+constructor which is able to create new deferred objects that can check
+for the existence of a promise to establish whether the object can be
+observed. It can also invoke callback queues and pass on the success of
+synchronous and asynchronous functions. It's quite essential to note
+that the default state of any Deferred object is unresolved. Callbacks
+which may be added to it through .then() or .fail() are queued up and get
+executed later on in the process.
+
+You are able to use Deferred objects in conjunction with the promise concept of
+when(), implemented in jQuery as $.when() to wait for all of the Deferred
+object's requests to complete executing (ie. for all of the promises to be
+fulfilled). In technical terms, $.when() is effectively a way to execute
+callbacks based on any number of promises that represent asynchronous events.
+
+An example of $.when() accepting multiple arguments can be seen below in
+conjunction with .then():
+
+```
+function successFunc(){
+ console.log( "success!" );
+}
+
+function failureFunc(){
+ console.log( "failure!" );
+}
+
+$.when(
+ $.ajax( "/main.php" ),
+ $.ajax( "/modules.php" ),
+ $.ajax( "/lists.php" )
+).then( successFunc, failureFunc );
+```
+
+The $.when() implementation offered in jQuery is quite interesting as it not
+only interprets deferred objects, but when passed arguments that are not
+deferreds, it treats these as if they were resolved deferreds and executes any
+callbacks (doneCallbacks) right away. It is also worth noting that jQuery's
+deferred implementation, in addition to exposing deferred.then(), a jQuery
+promise also supports the deferred.done() and deferred.fail() methods which can
+also be used to add callbacks to the deferred's queues.
+
+We will now take a look at a code example that utilizes many of the deferred
+features mentioned in the table presented earlier. Here is a very basic
+application that consumes (1) an external news feed and (2) a reactions feed
+for pulling in the latest comments via $.get() (which will return a promise).
+The application also has a function (prepareInterface()) which returns a
+promise to complete animating our containers for both the news and
+reactions.
+
+
+```
+function getLatestNews() {
+ return $.get( "latestNews.php", function(data){
+ console.log( "news data received" );
+ $( ".news" ).html(data);
+ } );
+}
+
+function getLatestReactions() {
+ return $.get( "latestReactions.php", function(data){
+ console.log( "reactions data received" );
+ $( ".reactions" ).html(data);
+ } );
+}
+
+function prepareInterface() {
+ return $.Deferred(function( dfd ) {
+ var latest = $( ".news, .reactions" );
+ latest.slideDown( 500, dfd.resolve );
+ latest.addClass( "active" );
+ }).promise();
+}
+
+$.when(
+ getLatestNews(),
+ getLatestReactions(),
+ prepareInterface()
+).then(function(){
+ console.log( "fire after requests succeed" );
+}).fail(function(){
+ console.log( "something went wrong!" );
+});
+```
Something went wrong with that request. Please try again.