|
| 1 | +--- |
| 2 | +title: Deferreds |
| 3 | +level: advanced |
| 4 | +source: http://msdn.microsoft.com/en-us/magazine/gg723713.aspx |
| 5 | +attribution: |
| 6 | + - Julian Aubourg <j@ubourg.net> |
| 7 | + - Addy Osmani <addyosmani@gmail.com> |
| 8 | + - Andree Hansson <peolanha@gmail.com> |
| 9 | +--- |
| 10 | + |
| 11 | +At a high-level, deferreds can be thought of as a way to represent |
| 12 | +asynchronous operations which can take a long time to complete. They're the |
| 13 | +asynchronous alternative to blocking functions and the general idea is |
| 14 | +that rather than your application blocking while it awaits some request |
| 15 | +to complete before returning a result, a deferred object can instead be |
| 16 | +returned immediately. You can then attach callbacks to the deferred |
| 17 | +object: they will be called once the request has actually completed. |
| 18 | + |
| 19 | +##Promises |
| 20 | + |
| 21 | +In its most basic form, a 'promise' is a model that provides a solution |
| 22 | +for the concept of deferred (or future) results in software engineering. |
| 23 | +The main idea behind it is something we've already covered: rather than |
| 24 | +executing a call which may result in blocking, we instead return a |
| 25 | +promise for a future value that will eventually be satisfied. |
| 26 | + |
| 27 | +If it helps to have an example here, consider that you are building a |
| 28 | +web application which heavily relies on data from a third party API. A |
| 29 | +common problem that's faced is having an unknown knowledge of the API |
| 30 | +server's latency at a given time so it's possible that other parts of |
| 31 | +your application may be blocked from running until a result from it is |
| 32 | +returned. Deferreds provide a better solution to this problem, one which |
| 33 | +is void of 'blocking' effects and completely decoupled. |
| 34 | + |
| 35 | +The [Promise/A](http://wiki.commonjs.org/wiki/Promises/A) proposal |
| 36 | +defines a method called 'then' that can be used to register callbacks to |
| 37 | +a promise and, thus, get the future result when it is available. The |
| 38 | +pseudo-code for dealing with a third party API that returns a promise |
| 39 | +may look like: |
| 40 | + |
| 41 | +``` |
| 42 | +promise = callToAPI( arg1, arg2, ...); |
| 43 | +
|
| 44 | +promise.then(function( futureValue ) { |
| 45 | + /* handle futureValue */ |
| 46 | +}); |
| 47 | + |
| 48 | +promise.then(function( futureValue ) { |
| 49 | + /* do something else */ |
| 50 | +}); |
| 51 | +``` |
| 52 | + |
| 53 | +Furthermore, a promise can actually end up being in two different |
| 54 | +states: |
| 55 | + |
| 56 | +- resolved: in which case data is available |
| 57 | +- rejected: in which case something went wrong and no value is |
| 58 | + available |
| 59 | + |
| 60 | +Thankfully, the 'then' method accepts two parameters: one for when the |
| 61 | +promise was resolved, another for when the promise was rejected. If we |
| 62 | +get back to pseudo-code, we may do things like: |
| 63 | + |
| 64 | +``` |
| 65 | +promise.then( function( futureValue ) { |
| 66 | + /* we got a value */ |
| 67 | +} , function() { |
| 68 | + /* something went wrong */ |
| 69 | +} ); |
| 70 | +``` |
| 71 | + |
| 72 | +In the case of certain applications, it is necessary to have several |
| 73 | +results returned before your application can continue at all (for |
| 74 | +example, displaying a dynamic set of options on a screen before a user |
| 75 | +is able to select the option that interests them).Where this is the |
| 76 | +case, a method called 'when' exists, which can be used to perform some |
| 77 | +action once all the promises have been fully fulfilled: |
| 78 | + |
| 79 | +``` |
| 80 | +when( |
| 81 | + promise1, |
| 82 | + promise2, |
| 83 | + ... |
| 84 | +).then(function( futureValue1, futureValue2, ... ) { |
| 85 | + /* all promises have completed and are resolved */ |
| 86 | +}); |
| 87 | +``` |
| 88 | + |
| 89 | +A good example is a scenario where you may have multiple concurrent |
| 90 | +animations that are being run. Without keeping track of each callback |
| 91 | +firing on completion, it can be difficult to truly establish once all |
| 92 | +your animations have finished running. Using promises and 'when' however |
| 93 | +this is very straightforward as each of your animations can effectively |
| 94 | +say 'we promise to let you know once we're done'. The compounded result |
| 95 | +of this means it's a trivial process to execute a single callback once |
| 96 | +the animations are done. For example: |
| 97 | + |
| 98 | +``` |
| 99 | +var promise1 = $("#id1").animate().promise(); |
| 100 | +var promise2 = $("#id2").animate().promise(); |
| 101 | +when( |
| 102 | + promise1, |
| 103 | + promise2 |
| 104 | +).then(function(){ |
| 105 | + /* once both animations have completed |
| 106 | + we can then run our additional logic */ |
| 107 | +}); |
| 108 | +``` |
| 109 | + |
| 110 | +This means that one can basically write non-blocking logic that can be |
| 111 | +executed without synchronization. Rather than directly passing callbacks |
| 112 | +to functions, something which can lead to tightly coupled interfaces, |
| 113 | +using promises allows one to separate concerns for code that is |
| 114 | +synchronous or asynchronous. |
0 commit comments