02-deferred.js | |
---|---|
jQuery Annotated Source. | |
Chapter 2: Deferred | |
Promise methods | var promiseMethods = "done fail isResolved isRejected promise then always pipe".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;
},
always: function() {
return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
},
fail: failDeferred.done,
rejectWith: failDeferred.resolveWith,
reject: failDeferred.resolve,
isRejected: failDeferred.isResolved,
pipe: function( fnDone, fnFail ) {
return jQuery.Deferred(function( newDefer ) {
jQuery.each( {
done: [ fnDone, "resolve" ],
fail: [ fnFail, "reject" ]
}, function( handler, data ) {
var fn = data[ 0 ],
action = data[ 1 ],
returned;
if ( jQuery.isFunction( fn ) ) {
deferred[ handler ](function() {
returned = fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise().then( newDefer.resolve, newDefer.reject );
} else {
newDefer[ action ]( returned );
}
});
} else {
deferred[ handler ]( newDefer[ action ] );
}
});
}).promise();
}, |
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 ) ) { |
Strange bug in FF4: Values changed onto the arguments object sometimes end up as undefined values outside the $.when method. Cloning the object into a fresh array solves the issue | deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
}
};
}
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();
}
});
|