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
174
src/core.js
174
src/core.js
|
@ -50,15 +50,9 @@ var jQuery = function( selector, context ) {
|
|||
// For matching the engine and version of the browser
|
||||
browserMatch,
|
||||
|
||||
// Has the ready events already been bound?
|
||||
readyBound = false,
|
||||
|
||||
// The deferred used on DOM ready
|
||||
readyList,
|
||||
|
||||
// Promise methods
|
||||
promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
|
||||
|
||||
// The ready event handler
|
||||
DOMContentLoaded,
|
||||
|
||||
|
@ -408,11 +402,11 @@ jQuery.extend({
|
|||
},
|
||||
|
||||
bindReady: function() {
|
||||
if ( readyBound ) {
|
||||
if ( readyList ) {
|
||||
return;
|
||||
}
|
||||
|
||||
readyBound = true;
|
||||
readyList = jQuery._Deferred();
|
||||
|
||||
// Catch cases where $(document).ready() is called after the
|
||||
// browser event has already occurred.
|
||||
|
@ -792,167 +786,6 @@ jQuery.extend({
|
|||
return (new Date()).getTime();
|
||||
},
|
||||
|
||||
// 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( jQuery.isFunction( this.promise ) ? this.promise() : 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( object ) {
|
||||
var lastIndex = arguments.length,
|
||||
deferred = lastIndex <= 1 && object && jQuery.isFunction( object.promise ) ?
|
||||
object :
|
||||
jQuery.Deferred(),
|
||||
promise = deferred.promise();
|
||||
|
||||
if ( lastIndex > 1 ) {
|
||||
var array = slice.call( arguments, 0 ),
|
||||
count = lastIndex,
|
||||
iCallback = function( index ) {
|
||||
return function( value ) {
|
||||
array[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value;
|
||||
if ( !( --count ) ) {
|
||||
deferred.resolveWith( promise, array );
|
||||
}
|
||||
};
|
||||
};
|
||||
while( ( lastIndex-- ) ) {
|
||||
object = array[ lastIndex ];
|
||||
if ( object && jQuery.isFunction( object.promise ) ) {
|
||||
object.promise().then( iCallback(lastIndex), deferred.reject );
|
||||
} else {
|
||||
--count;
|
||||
}
|
||||
}
|
||||
if ( !count ) {
|
||||
deferred.resolveWith( promise, array );
|
||||
}
|
||||
} else if ( deferred !== object ) {
|
||||
deferred.resolve( object );
|
||||
}
|
||||
return promise;
|
||||
},
|
||||
|
||||
// Use of jQuery.browser is frowned upon.
|
||||
// More details: http://docs.jquery.com/Utilities/jQuery.browser
|
||||
uaMatch: function( ua ) {
|
||||
|
@ -991,9 +824,6 @@ jQuery.extend({
|
|||
browser: {}
|
||||
});
|
||||
|
||||
// Create readyList deferred
|
||||
readyList = jQuery._Deferred();
|
||||
|
||||
// Populate the class2type map
|
||||
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
|
||||
class2type[ "[object " + name + "]" ] = name.toLowerCase();
|
||||
|
|
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