Skip to content

Commit f0532a2

Browse files
committed
Callbacks: bring back size reduction
Ref 4cbf02d
1 parent e2af987 commit f0532a2

File tree

1 file changed

+71
-87
lines changed

1 file changed

+71
-87
lines changed

src/callbacks.js

Lines changed: 71 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@ define( [
33
"./var/rnotwhite"
44
], function( jQuery, rnotwhite ) {
55

6-
// String to Object options format cache
7-
var optionsCache = {};
8-
9-
// Convert String-formatted options into Object-formatted ones and store in cache
6+
// Convert String-formatted options into Object-formatted ones
107
function createOptions( options ) {
11-
var object = optionsCache[ options ] = {};
8+
var object = {};
129
jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
1310
object[ flag ] = true;
1411
} );
@@ -42,71 +39,71 @@ jQuery.Callbacks = function( options ) {
4239
// Convert options from String-formatted to Object-formatted if needed
4340
// (we check in cache first)
4441
options = typeof options === "string" ?
45-
( optionsCache[ options ] || createOptions( options ) ) :
42+
createOptions( options ) :
4643
jQuery.extend( {}, options );
4744

4845
var // Flag to know if list is currently firing
4946
firing,
5047

51-
// Last fire value (for non-forgettable lists)
48+
// Last fire value for non-forgettable lists
5249
memory,
5350

5451
// Flag to know if list was already fired
5552
fired,
5653

57-
// Flag to prevent .fire/.fireWith
54+
// Flag to prevent firing
5855
locked,
5956

60-
// End of the loop when firing
61-
firingLength,
62-
63-
// Index of currently firing callback (modified by remove if needed)
64-
firingIndex,
65-
66-
// First callback to fire (used internally by add and fireWith)
67-
firingStart,
68-
6957
// Actual callback list
7058
list = [],
7159

72-
// Stack of fire calls for repeatable lists
73-
stack = !options.once && [],
60+
// Queue of execution data for repeatable lists
61+
queue = [],
62+
63+
// Index of currently firing callback (modified by add/remove as needed)
64+
firingIndex = -1,
7465

7566
// Fire callbacks
76-
fire = function( data ) {
67+
fire = function() {
68+
69+
// Enforce single-firing
7770
locked = options.once;
78-
memory = options.memory && data;
79-
fired = true;
80-
firingIndex = firingStart || 0;
81-
firingStart = 0;
82-
firingLength = list.length;
83-
firing = true;
84-
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
85-
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false &&
86-
options.stopOnFalse ) {
87-
88-
memory = false; // To prevent further calls using add
89-
break;
71+
72+
// Execute callbacks for all pending executions,
73+
// respecting firingIndex overrides and runtime changes
74+
fired = firing = true;
75+
for ( ; queue.length; firingIndex = -1 ) {
76+
memory = queue.shift();
77+
while ( ++firingIndex < list.length ) {
78+
79+
// Run callback and check for early termination
80+
if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
81+
options.stopOnFalse ) {
82+
83+
// Jump to end and forget the data so .add doesn't re-fire
84+
firingIndex = list.length;
85+
memory = false;
86+
}
9087
}
9188
}
92-
firing = false;
9389

94-
// If not disabled,
95-
if ( list ) {
90+
// Forget the data if we're done with it
91+
if ( !options.memory ) {
92+
memory = false;
93+
}
94+
95+
firing = false;
9696

97-
// If repeatable, check for pending execution
98-
if ( stack ) {
99-
if ( stack.length ) {
100-
fire( stack.shift() );
101-
}
97+
// Clean up if we're done firing for good
98+
if ( locked ) {
10299

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

107-
// Else, disable
104+
// Otherwise, this object is spent
108105
} else {
109-
self.disable();
106+
list = "";
110107
}
111108
}
112109
},
@@ -118,72 +115,61 @@ jQuery.Callbacks = function( options ) {
118115
add: function() {
119116
if ( list ) {
120117

121-
// First, we save the current length
122-
var start = list.length;
118+
// If we have memory from a past run, we should fire after adding
119+
if ( memory && !firing ) {
120+
firingIndex = list.length - 1;
121+
queue.push( memory );
122+
}
123+
123124
( function add( args ) {
124125
jQuery.each( args, function( _, arg ) {
125-
var type = jQuery.type( arg );
126-
if ( type === "function" ) {
126+
if ( jQuery.isFunction( arg ) ) {
127127
if ( !options.unique || !self.has( arg ) ) {
128128
list.push( arg );
129129
}
130-
} else if ( arg && arg.length && type !== "string" ) {
130+
} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
131131

132132
// Inspect recursively
133133
add( arg );
134134
}
135135
} );
136136
} )( arguments );
137137

138-
// Do we need to add the callbacks to the
139-
// current firing batch?
140-
if ( firing ) {
141-
firingLength = list.length;
142-
143-
// With memory, if we're not firing then
144-
// we should call right away
145-
} else if ( memory ) {
146-
firingStart = start;
147-
fire( memory );
138+
if ( memory && !firing ) {
139+
fire();
148140
}
149141
}
150142
return this;
151143
},
152144

153145
// Remove a callback from the list
154146
remove: function() {
155-
if ( list ) {
156-
jQuery.each( arguments, function( _, arg ) {
157-
var index;
158-
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
159-
list.splice( index, 1 );
160-
161-
// Handle firing indexes
162-
if ( firing ) {
163-
if ( index <= firingLength ) {
164-
firingLength--;
165-
}
166-
if ( index <= firingIndex ) {
167-
firingIndex--;
168-
}
169-
}
147+
jQuery.each( arguments, function( _, arg ) {
148+
var index;
149+
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
150+
list.splice( index, 1 );
151+
152+
// Handle firing indexes
153+
if ( index <= firingIndex ) {
154+
firingIndex--;
170155
}
171-
} );
172-
}
156+
}
157+
} );
173158
return this;
174159
},
175160

176161
// Check if a given callback is in the list.
177162
// If no argument is given, return whether or not list has callbacks attached.
178163
has: function( fn ) {
179-
return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
164+
return fn ?
165+
jQuery.inArray( fn, list ) > -1 :
166+
list.length > 0;
180167
},
181168

182169
// Remove all callbacks from the list
183170
empty: function() {
184171
if ( list ) {
185172
list = [];
186-
firingLength = 0;
187173
}
188174
return this;
189175
},
@@ -192,8 +178,8 @@ jQuery.Callbacks = function( options ) {
192178
// Abort any current/pending executions
193179
// Clear all callbacks and values
194180
disable: function() {
195-
list = stack = memory = undefined;
196-
locked = true;
181+
locked = queue = [];
182+
list = memory = "";
197183
return this;
198184
},
199185
disabled: function() {
@@ -204,10 +190,9 @@ jQuery.Callbacks = function( options ) {
204190
// Also disable .add unless we have memory (since it would have no effect)
205191
// Abort any pending executions
206192
lock: function() {
207-
stack = undefined;
208-
locked = true;
193+
locked = queue = [];
209194
if ( !memory ) {
210-
self.disable();
195+
list = memory = "";
211196
}
212197
return this;
213198
},
@@ -220,10 +205,9 @@ jQuery.Callbacks = function( options ) {
220205
if ( !locked ) {
221206
args = args || [];
222207
args = [ context, args.slice ? args.slice() : args ];
223-
if ( firing ) {
224-
stack.push( args );
225-
} else {
226-
fire( args );
208+
queue.push( args );
209+
if ( !firing ) {
210+
fire();
227211
}
228212
}
229213
return this;

0 commit comments

Comments
 (0)