Callbacks: Reduce size

(cherry picked from commit 18baae2efb)
This commit is contained in:
Richard Gibson 2015-01-03 20:48:54 -05:00
parent 32bf9178ca
commit 4cbf02df84

View File

@ -3,12 +3,9 @@ define([
"./var/rnotwhite"
], function( jQuery, rnotwhite ) {
// String to Object options format cache
var optionsCache = {};
// Convert String-formatted options into Object-formatted ones and store in cache
// Convert String-formatted options into Object-formatted ones
function createOptions( options ) {
var object = optionsCache[ options ] = {};
var object = {};
jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
object[ flag ] = true;
});
@ -42,94 +39,96 @@ jQuery.Callbacks = function( options ) {
// Convert options from String-formatted to Object-formatted if needed
// (we check in cache first)
options = typeof options === "string" ?
( optionsCache[ options ] || createOptions( options ) ) :
createOptions( options ) :
jQuery.extend( {}, options );
var // Flag to know if list is currently firing
firing,
// Last fire value (for non-forgettable lists)
// Last fire value for non-forgettable lists
memory,
// Flag to know if list was already fired
fired,
// Flag to prevent .fire/.fireWith
// Flag to prevent firing
locked,
// End of the loop when firing
firingLength,
// Index of currently firing callback (modified by remove if needed)
firingIndex,
// First callback to fire (used internally by add and fireWith)
firingStart,
// Actual callback list
list = [],
// Stack of fire calls for repeatable lists
stack = !options.once && [],
// Queue of execution data for repeatable lists
queue = [],
// Index of currently firing callback (modified by add/remove as needed)
firingIndex = -1,
// Fire callbacks
fire = function( data ) {
locked = options.once;
memory = options.memory && data;
fired = true;
firingIndex = firingStart || 0;
firingStart = 0;
firingLength = list.length;
firing = true;
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false &&
options.stopOnFalse ) {
fire = function() {
memory = false; // To prevent further calls using add
break;
// Enforce single-firing
locked = options.once;
// Execute callbacks for all pending executions,
// respecting firingIndex overrides and runtime changes
fired = firing = true;
for ( ; queue.length; firingIndex = -1 ) {
memory = queue.shift();
while ( ++firingIndex < list.length ) {
// Run callback and check for early termination
if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
options.stopOnFalse ) {
// Jump to end and forget the data so .add doesn't re-fire
firingIndex = list.length;
memory = false;
}
}
}
// Forget the data if we're done with it
if ( !options.memory ) {
memory = false;
}
firing = false;
// If not disabled,
if ( list ) {
// Clean up if we're done firing for good
if ( locked ) {
// If repeatable, check for pending execution
if ( stack ) {
if ( stack.length ) {
fire( stack.shift() );
}
// If not repeatable but with memory, clear out spent callbacks
} else if ( memory ) {
// Keep an empty list if we have data for future add calls
if ( memory ) {
list = [];
// Else, disable
// Otherwise, this object is spent
} else {
self.disable();
list = "";
}
}
},
// Actual Callbacks object
self = {
// Add a callback or a collection of callbacks to the list
add: function() {
if ( list ) {
// First, we save the current length
var start = list.length;
// If we have memory from a past run, we should fire after adding
if ( memory && !firing ) {
firingIndex = list.length - 1;
queue.push( memory );
}
(function add( args ) {
jQuery.each( args, function( _, arg ) {
var type = jQuery.type( arg );
if ( type === "function" ) {
if ( jQuery.isFunction( arg ) ) {
if ( !options.unique || !self.has( arg ) ) {
list.push( arg );
}
} else if ( arg && arg.length && type !== "string" ) {
} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
// Inspect recursively
add( arg );
}
});
})( arguments );
// Do we need to add the callbacks to the
// current firing batch?
if ( firing ) {
firingLength = list.length;
// With memory, if we're not firing then
// we should call right away
} else if ( memory ) {
firingStart = start;
fire( memory );
if ( memory && !firing ) {
fire();
}
}
return this;
@ -137,37 +136,32 @@ jQuery.Callbacks = function( options ) {
// Remove a callback from the list
remove: function() {
if ( list ) {
jQuery.each( arguments, function( _, arg ) {
var index;
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
list.splice( index, 1 );
// Handle firing indexes
if ( firing ) {
if ( index <= firingLength ) {
firingLength--;
}
if ( index <= firingIndex ) {
firingIndex--;
}
}
jQuery.each( arguments, function( _, arg ) {
var index;
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
list.splice( index, 1 );
// Handle firing indexes
if ( index <= firingIndex ) {
firingIndex--;
}
});
}
}
});
return this;
},
// Check if a given callback is in the list.
// If no argument is given, return whether or not list has callbacks attached.
has: function( fn ) {
return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
return fn ?
jQuery.inArray( fn, list ) > -1 :
list.length > 0;
},
// Remove all callbacks from the list
empty: function() {
if ( list ) {
list = [];
firingLength = 0;
}
return this;
},
@ -176,8 +170,8 @@ jQuery.Callbacks = function( options ) {
// Abort any current/pending executions
// Clear all callbacks and values
disable: function() {
list = stack = memory = undefined;
locked = true;
locked = queue = [];
list = memory = "";
return this;
},
disabled: function() {
@ -188,10 +182,9 @@ jQuery.Callbacks = function( options ) {
// Also disable .add unless we have memory (since it would have no effect)
// Abort any pending executions
lock: function() {
stack = undefined;
locked = true;
locked = queue = [];
if ( !memory && !firing ) {
self.disable();
list = memory = "";
}
return this;
},
@ -204,10 +197,9 @@ jQuery.Callbacks = function( options ) {
if ( !locked ) {
args = args || [];
args = [ context, args.slice ? args.slice() : args ];
if ( firing ) {
stack.push( args );
} else {
fire( args );
queue.push( args );
if ( !firing ) {
fire();
}
}
return this;