Skip to content

Commit

Permalink
Callbacks: Reduce size
Browse files Browse the repository at this point in the history
  • Loading branch information
gibson042 committed Jan 11, 2015
1 parent fc7477f commit 18baae2
Showing 1 changed file with 74 additions and 82 deletions.
156 changes: 74 additions & 82 deletions src/callbacks.js
Expand Up @@ -3,12 +3,9 @@ define([
"./var/rnotwhite" "./var/rnotwhite"
], function( jQuery, rnotwhite ) { ], function( jQuery, rnotwhite ) {


// String to Object options format cache // Convert String-formatted options into Object-formatted ones
var optionsCache = {};

// Convert String-formatted options into Object-formatted ones and store in cache
function createOptions( options ) { function createOptions( options ) {
var object = optionsCache[ options ] = {}; var object = {};
jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
object[ flag ] = true; object[ flag ] = true;
}); });
Expand Down Expand Up @@ -42,132 +39,129 @@ jQuery.Callbacks = function( options ) {
// Convert options from String-formatted to Object-formatted if needed // Convert options from String-formatted to Object-formatted if needed
// (we check in cache first) // (we check in cache first)
options = typeof options === "string" ? options = typeof options === "string" ?
( optionsCache[ options ] || createOptions( options ) ) : createOptions( options ) :
jQuery.extend( {}, options ); jQuery.extend( {}, options );


var // Flag to know if list is currently firing var // Flag to know if list is currently firing
firing, firing,
// Last fire value (for non-forgettable lists) // Last fire value for non-forgettable lists
memory, memory,
// Flag to know if list was already fired // Flag to know if list was already fired
fired, fired,
// Flag to prevent .fire/.fireWith // Flag to prevent firing
locked, 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 // Actual callback list
list = [], list = [],
// Stack of fire calls for repeatable lists // Queue of execution data for repeatable lists
stack = !options.once && [], queue = [],
// Index of currently firing callback (modified by add/remove as needed)
firingIndex = -1,
// Fire callbacks // Fire callbacks
fire = function( data ) { fire = function() {

// Enforce single-firing
locked = options.once; locked = options.once;
memory = options.memory && data;
fired = true; // Execute callbacks for all pending executions,
firingIndex = firingStart || 0; // respecting firingIndex overrides and runtime changes
firingStart = 0; fired = firing = true;
firingLength = list.length; for ( ; queue.length; firingIndex = -1 ) {
firing = true; memory = queue.shift();
for ( ; list && firingIndex < firingLength; firingIndex++ ) { while ( ++firingIndex < list.length ) {
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false &&
options.stopOnFalse ) { // Run callback and check for early termination

if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
memory = false; // To prevent further calls using add options.stopOnFalse ) {
break;
// Jump to end and forget the data so .add doesn't re-fire
firingIndex = list.length;
memory = false;
}
} }
} }
firing = false;


// If not disabled, // Forget the data if we're done with it
if ( list ) { if ( !options.memory ) {
memory = false;
}


// If repeatable, check for pending execution firing = false;
if ( stack ) {
if ( stack.length ) { // Clean up if we're done firing for good
fire( stack.shift() ); if ( locked ) {
}


// If not repeatable but with memory, clear out spent callbacks // Keep an empty list if we have data for future add calls
} else if ( memory ) { if ( memory ) {
list = []; list = [];


// Else, disable // Otherwise, this object is spent
} else { } else {
self.disable(); list = "";
} }
} }
}, },

// Actual Callbacks object // Actual Callbacks object
self = { self = {

// Add a callback or a collection of callbacks to the list // Add a callback or a collection of callbacks to the list
add: function() { add: function() {
if ( list ) { 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 ) { (function add( args ) {
jQuery.each( args, function( _, arg ) { jQuery.each( args, function( _, arg ) {
var type = jQuery.type( arg ); if ( jQuery.isFunction( arg ) ) {
if ( type === "function" ) {
if ( !options.unique || !self.has( arg ) ) { if ( !options.unique || !self.has( arg ) ) {
list.push( arg ); list.push( arg );
} }
} else if ( arg && arg.length && type !== "string" ) { } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
// Inspect recursively // Inspect recursively
add( arg ); add( arg );
} }
}); });
})( arguments ); })( arguments );
// Do we need to add the callbacks to the
// current firing batch? if ( memory && !firing ) {
if ( firing ) { fire();
firingLength = list.length;
// With memory, if we're not firing then
// we should call right away
} else if ( memory ) {
firingStart = start;
fire( memory );
} }
} }
return this; return this;
}, },


// Remove a callback from the list // Remove a callback from the list
remove: function() { remove: function() {
if ( list ) { jQuery.each( arguments, function( _, arg ) {
jQuery.each( arguments, function( _, arg ) { var index;
var index; while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { list.splice( index, 1 );
list.splice( index, 1 );
// Handle firing indexes // Handle firing indexes
if ( firing ) { if ( index <= firingIndex ) {
if ( index <= firingLength ) { firingIndex--;
firingLength--;
}
if ( index <= firingIndex ) {
firingIndex--;
}
}
} }
}); }
} });
return this; return this;
}, },


// Check if a given callback is in the list. // Check if a given callback is in the list.
// If no argument is given, return whether or not list has callbacks attached. // If no argument is given, return whether or not list has callbacks attached.
has: function( fn ) { 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 // Remove all callbacks from the list
empty: function() { empty: function() {
if ( list ) { if ( list ) {
list = []; list = [];
firingLength = 0;
} }
return this; return this;
}, },
Expand All @@ -176,8 +170,8 @@ jQuery.Callbacks = function( options ) {
// Abort any current/pending executions // Abort any current/pending executions
// Clear all callbacks and values // Clear all callbacks and values
disable: function() { disable: function() {
list = stack = memory = undefined; locked = queue = [];
locked = true; list = memory = "";
return this; return this;
}, },
disabled: function() { disabled: function() {
Expand All @@ -188,10 +182,9 @@ jQuery.Callbacks = function( options ) {
// Also disable .add unless we have memory (since it would have no effect) // Also disable .add unless we have memory (since it would have no effect)
// Abort any pending executions // Abort any pending executions
lock: function() { lock: function() {
stack = undefined; locked = queue = [];
locked = true;
if ( !memory && !firing ) { if ( !memory && !firing ) {
self.disable(); list = memory = "";
} }
return this; return this;
}, },
Expand All @@ -204,10 +197,9 @@ jQuery.Callbacks = function( options ) {
if ( !locked ) { if ( !locked ) {
args = args || []; args = args || [];
args = [ context, args.slice ? args.slice() : args ]; args = [ context, args.slice ? args.slice() : args ];
if ( firing ) { queue.push( args );
stack.push( args ); if ( !firing ) {
} else { fire();
fire( args );
} }
} }
return this; return this;
Expand Down

0 comments on commit 18baae2

Please sign in to comment.