Moves Deferred-related code into a separate module. Context handling has been simplified in _Deferred.resolve and jQuery.when has been refactored for clarity (and minor optimization).
This commit is contained in:
parent
c1279895f3
commit
2d0bc7ce72
17 changed files with 407 additions and 393 deletions
169
src/deferred.js
Normal file
169
src/deferred.js
Normal file
|
@ -0,0 +1,169 @@
|
|||
(function( jQuery ) {
|
||||
|
||||
var // Promise methods
|
||||
promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
|
||||
// Static reference to slice
|
||||
sliceDeferred = [].slice;
|
||||
|
||||
jQuery.extend({
|
||||
// Create a simple deferred (one callbacks list)
|
||||
_Deferred: function() {
|
||||
var // callbacks list
|
||||
callbacks = [],
|
||||
// stored [ context , args ]
|
||||
fired,
|
||||
// to avoid firing when already doing so
|
||||
firing,
|
||||
// flag to know if the deferred has been cancelled
|
||||
cancelled,
|
||||
// the deferred itself
|
||||
deferred = {
|
||||
|
||||
// done( f1, f2, ...)
|
||||
done: function() {
|
||||
if ( !cancelled ) {
|
||||
var args = arguments,
|
||||
i,
|
||||
length,
|
||||
elem,
|
||||
type,
|
||||
_fired;
|
||||
if ( fired ) {
|
||||
_fired = fired;
|
||||
fired = 0;
|
||||
}
|
||||
for ( i = 0, length = args.length; i < length; i++ ) {
|
||||
elem = args[ i ];
|
||||
type = jQuery.type( elem );
|
||||
if ( type === "array" ) {
|
||||
deferred.done.apply( deferred, elem );
|
||||
} else if ( type === "function" ) {
|
||||
callbacks.push( elem );
|
||||
}
|
||||
}
|
||||
if ( _fired ) {
|
||||
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// resolve with given context and args
|
||||
resolveWith: function( context, args ) {
|
||||
if ( !cancelled && !fired && !firing ) {
|
||||
// make sure args are available (#8421)
|
||||
args = args || [];
|
||||
firing = 1;
|
||||
try {
|
||||
while( callbacks[ 0 ] ) {
|
||||
callbacks.shift().apply( context, args );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
fired = [ context, args ];
|
||||
firing = 0;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// resolve with this as context and given arguments
|
||||
resolve: function() {
|
||||
deferred.resolveWith( this, arguments );
|
||||
return this;
|
||||
},
|
||||
|
||||
// Has this deferred been resolved?
|
||||
isResolved: function() {
|
||||
return !!( firing || fired );
|
||||
},
|
||||
|
||||
// Cancel
|
||||
cancel: function() {
|
||||
cancelled = 1;
|
||||
callbacks = [];
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
return deferred;
|
||||
},
|
||||
|
||||
// Full fledged deferred (two callbacks list)
|
||||
Deferred: function( func ) {
|
||||
var deferred = jQuery._Deferred(),
|
||||
failDeferred = jQuery._Deferred(),
|
||||
promise;
|
||||
// Add errorDeferred methods, then and promise
|
||||
jQuery.extend( deferred, {
|
||||
then: function( doneCallbacks, failCallbacks ) {
|
||||
deferred.done( doneCallbacks ).fail( failCallbacks );
|
||||
return this;
|
||||
},
|
||||
fail: failDeferred.done,
|
||||
rejectWith: failDeferred.resolveWith,
|
||||
reject: failDeferred.resolve,
|
||||
isRejected: failDeferred.isResolved,
|
||||
// Get a promise for this deferred
|
||||
// If obj is provided, the promise aspect is added to the object
|
||||
promise: function( obj ) {
|
||||
if ( obj == null ) {
|
||||
if ( promise ) {
|
||||
return promise;
|
||||
}
|
||||
promise = obj = {};
|
||||
}
|
||||
var i = promiseMethods.length;
|
||||
while( i-- ) {
|
||||
obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
} );
|
||||
// Make sure only one callback list will be used
|
||||
deferred.done( failDeferred.cancel ).fail( deferred.cancel );
|
||||
// Unexpose cancel
|
||||
delete deferred.cancel;
|
||||
// Call given func if any
|
||||
if ( func ) {
|
||||
func.call( deferred, deferred );
|
||||
}
|
||||
return deferred;
|
||||
},
|
||||
|
||||
// Deferred helper
|
||||
when: function( firstParam ) {
|
||||
var args = arguments,
|
||||
i = 0,
|
||||
length = args.length,
|
||||
count = length,
|
||||
deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
|
||||
firstParam :
|
||||
jQuery.Deferred();
|
||||
function resolveFunc( i ) {
|
||||
return function( value ) {
|
||||
args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
|
||||
if ( !( --count ) ) {
|
||||
deferred.resolveWith( deferred, args );
|
||||
}
|
||||
};
|
||||
}
|
||||
if ( length > 1 ) {
|
||||
for( ; i < length; i++ ) {
|
||||
if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
|
||||
args[ i ].promise().then( resolveFunc(i), deferred.reject );
|
||||
} else {
|
||||
--count;
|
||||
}
|
||||
}
|
||||
if ( !count ) {
|
||||
deferred.resolveWith( deferred, args );
|
||||
}
|
||||
} else if ( deferred !== firstParam ) {
|
||||
deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
|
||||
}
|
||||
return deferred.promise();
|
||||
}
|
||||
});
|
||||
|
||||
})( jQuery );
|
Loading…
Add table
Add a link
Reference in a new issue