4 promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ),
5 // Static reference to slice
6 sliceDeferred = [].slice;
9 // Create a simple deferred (one callbacks list)
10 _Deferred: function() {
13 // stored [ context , args ]
15 // to avoid firing when already doing so
17 // flag to know if the deferred has been cancelled
19 // the deferred itself
35 for ( i = 0, length = args.length; i < length; i++ ) {
37 type = jQuery.type( elem );
38 if ( type === "array" ) {
39 deferred.done.apply( deferred, elem );
40 } else if ( type === "function" ) {
41 callbacks.push( elem );
45 deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
51 // resolve with given context and args
52 resolveWith: function( context, args ) {
53 if ( !cancelled && !fired && !firing ) {
54 // make sure args are available (#8421)
58 while( callbacks[ 0 ] ) {
59 callbacks.shift().apply( context, args );
63 fired = [ context, args ];
70 // resolve with this as context and given arguments
72 deferred.resolveWith( this, arguments );
76 // Has this deferred been resolved?
77 isResolved: function() {
78 return !!( firing || fired );
92 // Full fledged deferred (two callbacks list)
93 Deferred: function( func ) {
94 var deferred = jQuery._Deferred(),
95 failDeferred = jQuery._Deferred(),
97 // Add errorDeferred methods, then and promise
98 jQuery.extend( deferred, {
99 then: function( doneCallbacks, failCallbacks ) {
100 deferred.done( doneCallbacks ).fail( failCallbacks );
104 return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
106 fail: failDeferred.done,
107 rejectWith: failDeferred.resolveWith,
108 reject: failDeferred.resolve,
109 isRejected: failDeferred.isResolved,
110 pipe: function( fnDone, fnFail ) {
111 return jQuery.Deferred(function( newDefer ) {
113 done: [ fnDone, "resolve" ],
114 fail: [ fnFail, "reject" ]
115 }, function( handler, data ) {
119 if ( jQuery.isFunction( fn ) ) {
120 deferred[ handler ](function() {
121 returned = fn.apply( this, arguments );
122 if ( returned && jQuery.isFunction( returned.promise ) ) {
123 returned.promise().then( newDefer.resolve, newDefer.reject );
125 newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
129 deferred[ handler ]( newDefer[ action ] );
134 // Get a promise for this deferred
135 // If obj is provided, the promise aspect is added to the object
136 promise: function( obj ) {
143 var i = promiseMethods.length;
145 obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
150 // Make sure only one callback list will be used
151 deferred.done( failDeferred.cancel ).fail( deferred.cancel );
153 delete deferred.cancel;
154 // Call given func if any
156 func.call( deferred, deferred );
162 when: function( firstParam ) {
163 var args = arguments,
165 length = args.length,
167 deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
170 function resolveFunc( i ) {
171 return function( value ) {
172 args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
173 if ( !( --count ) ) {
174 // Strange bug in FF4:
175 // Values changed onto the arguments object sometimes end up as undefined values
176 // outside the $.when method. Cloning the object into a fresh array solves the issue
177 deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
182 for( ; i < length; i++ ) {
183 if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
184 args[ i ].promise().then( resolveFunc(i), deferred.reject );
190 deferred.resolveWith( deferred, args );
192 } else if ( deferred !== firstParam ) {
193 deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
195 return deferred.promise();