Release: push dist to same remote as project
[jquery.git] / src / deferred.js
blob939b58f37e4494553f290f4154709418d37b9d20
1 define([
2         "./core",
3         "./var/slice",
4         "./callbacks"
5 ], function( jQuery, slice ) {
7 jQuery.extend({
9         Deferred: function( func ) {
10                 var tuples = [
11                                 // action, add listener, listener list, final state
12                                 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
13                                 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
14                                 [ "notify", "progress", jQuery.Callbacks("memory") ]
15                         ],
16                         state = "pending",
17                         promise = {
18                                 state: function() {
19                                         return state;
20                                 },
21                                 always: function() {
22                                         deferred.done( arguments ).fail( arguments );
23                                         return this;
24                                 },
25                                 then: function( /* fnDone, fnFail, fnProgress */ ) {
26                                         var fns = arguments;
27                                         return jQuery.Deferred(function( newDefer ) {
28                                                 jQuery.each( tuples, function( i, tuple ) {
29                                                         var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
30                                                         // deferred[ done | fail | progress ] for forwarding actions to newDefer
31                                                         deferred[ tuple[1] ](function() {
32                                                                 var returned = fn && fn.apply( this, arguments );
33                                                                 if ( returned && jQuery.isFunction( returned.promise ) ) {
34                                                                         returned.promise()
35                                                                                 .done( newDefer.resolve )
36                                                                                 .fail( newDefer.reject )
37                                                                                 .progress( newDefer.notify );
38                                                                 } else {
39                                                                         newDefer[ tuple[ 0 ] + "With" ](
40                                                                                 this === promise ? newDefer.promise() : this,
41                                                                                 fn ? [ returned ] : arguments
42                                                                         );
43                                                                 }
44                                                         });
45                                                 });
46                                                 fns = null;
47                                         }).promise();
48                                 },
49                                 // Get a promise for this deferred
50                                 // If obj is provided, the promise aspect is added to the object
51                                 promise: function( obj ) {
52                                         return obj != null ? jQuery.extend( obj, promise ) : promise;
53                                 }
54                         },
55                         deferred = {};
57                 // Keep pipe for back-compat
58                 promise.pipe = promise.then;
60                 // Add list-specific methods
61                 jQuery.each( tuples, function( i, tuple ) {
62                         var list = tuple[ 2 ],
63                                 stateString = tuple[ 3 ];
65                         // promise[ done | fail | progress ] = list.add
66                         promise[ tuple[1] ] = list.add;
68                         // Handle state
69                         if ( stateString ) {
70                                 list.add(function() {
71                                         // state = [ resolved | rejected ]
72                                         state = stateString;
74                                 // [ reject_list | resolve_list ].disable; progress_list.lock
75                                 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
76                         }
78                         // deferred[ resolve | reject | notify ]
79                         deferred[ tuple[0] ] = function() {
80                                 deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
81                                 return this;
82                         };
83                         deferred[ tuple[0] + "With" ] = list.fireWith;
84                 });
86                 // Make the deferred a promise
87                 promise.promise( deferred );
89                 // Call given func if any
90                 if ( func ) {
91                         func.call( deferred, deferred );
92                 }
94                 // All done!
95                 return deferred;
96         },
98         // Deferred helper
99         when: function( subordinate /* , ..., subordinateN */ ) {
100                 var i = 0,
101                         resolveValues = slice.call( arguments ),
102                         length = resolveValues.length,
104                         // the count of uncompleted subordinates
105                         remaining = length !== 1 ||
106                                 ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
108                         // the master Deferred.
109                         // If resolveValues consist of only a single Deferred, just use that.
110                         deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
112                         // Update function for both resolve and progress values
113                         updateFunc = function( i, contexts, values ) {
114                                 return function( value ) {
115                                         contexts[ i ] = this;
116                                         values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
117                                         if ( values === progressValues ) {
118                                                 deferred.notifyWith( contexts, values );
119                                         } else if ( !( --remaining ) ) {
120                                                 deferred.resolveWith( contexts, values );
121                                         }
122                                 };
123                         },
125                         progressValues, progressContexts, resolveContexts;
127                 // Add listeners to Deferred subordinates; treat others as resolved
128                 if ( length > 1 ) {
129                         progressValues = new Array( length );
130                         progressContexts = new Array( length );
131                         resolveContexts = new Array( length );
132                         for ( ; i < length; i++ ) {
133                                 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
134                                         resolveValues[ i ].promise()
135                                                 .progress( updateFunc( i, progressContexts, progressValues ) )
136                                                 .done( updateFunc( i, resolveContexts, resolveValues ) )
137                                                 .fail( deferred.reject );
138                                 } else {
139                                         --remaining;
140                                 }
141                         }
142                 }
144                 // If we're not waiting on anything, resolve the master
145                 if ( !remaining ) {
146                         deferred.resolveWith( resolveContexts, resolveValues );
147                 }
149                 return deferred.promise();
150         }
153 return jQuery;