]> source.dussan.org Git - jquery.git/commitdiff
Callbacks: Reduce size
authorRichard Gibson <richard.gibson@gmail.com>
Sun, 4 Jan 2015 01:48:54 +0000 (20:48 -0500)
committerRichard Gibson <richard.gibson@gmail.com>
Sun, 11 Jan 2015 03:17:27 +0000 (22:17 -0500)
src/callbacks.js

index 4ce1bcdc571b296476dd9e9143413ba4dcaa830e..bec37ef54fa141d094274a9f9471ad2cfae54e63 100644 (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 ) {
+               fire = function() {
+
+                       // Enforce single-firing
                        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 ) {
-
-                                       memory = false; // To prevent further calls using add
-                                       break;
+
+                       // 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;
+                                       }
                                }
                        }
-                       firing = false;
 
-                       // If not disabled,
-                       if ( list ) {
+                       // Forget the data if we're done with it
+                       if ( !options.memory ) {
+                               memory = false;
+                       }
 
-                               // If repeatable, check for pending execution
-                               if ( stack ) {
-                                       if ( stack.length ) {
-                                               fire( stack.shift() );
-                                       }
+                       firing = false;
+
+                       // Clean up if we're done firing for good
+                       if ( locked ) {
 
-                               // 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;