Skip to content

Commit 4cbf02d

Browse files
committed
Callbacks: Reduce size
(cherry picked from commit 18baae2)
1 parent 32bf917 commit 4cbf02d

File tree

1 file changed

+74
-82
lines changed

1 file changed

+74
-82
lines changed

src/callbacks.js

Lines changed: 74 additions & 82 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,132 +39,129 @@ 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,
50-
// Last fire value (for non-forgettable lists)
47+
// Last fire value for non-forgettable lists
5148
memory,
5249
// Flag to know if list was already fired
5350
fired,
54-
// Flag to prevent .fire/.fireWith
51+
// Flag to prevent firing
5552
locked,
56-
// End of the loop when firing
57-
firingLength,
58-
// Index of currently firing callback (modified by remove if needed)
59-
firingIndex,
60-
// First callback to fire (used internally by add and fireWith)
61-
firingStart,
6253
// Actual callback list
6354
list = [],
64-
// Stack of fire calls for repeatable lists
65-
stack = !options.once && [],
55+
// Queue of execution data for repeatable lists
56+
queue = [],
57+
// Index of currently firing callback (modified by add/remove as needed)
58+
firingIndex = -1,
6659
// Fire callbacks
67-
fire = function( data ) {
60+
fire = function() {
61+
62+
// Enforce single-firing
6863
locked = options.once;
69-
memory = options.memory && data;
70-
fired = true;
71-
firingIndex = firingStart || 0;
72-
firingStart = 0;
73-
firingLength = list.length;
74-
firing = true;
75-
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
76-
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false &&
77-
options.stopOnFalse ) {
78-
79-
memory = false; // To prevent further calls using add
80-
break;
64+
65+
// Execute callbacks for all pending executions,
66+
// respecting firingIndex overrides and runtime changes
67+
fired = firing = true;
68+
for ( ; queue.length; firingIndex = -1 ) {
69+
memory = queue.shift();
70+
while ( ++firingIndex < list.length ) {
71+
72+
// Run callback and check for early termination
73+
if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
74+
options.stopOnFalse ) {
75+
76+
// Jump to end and forget the data so .add doesn't re-fire
77+
firingIndex = list.length;
78+
memory = false;
79+
}
8180
}
8281
}
83-
firing = false;
8482

85-
// If not disabled,
86-
if ( list ) {
83+
// Forget the data if we're done with it
84+
if ( !options.memory ) {
85+
memory = false;
86+
}
8787

88-
// If repeatable, check for pending execution
89-
if ( stack ) {
90-
if ( stack.length ) {
91-
fire( stack.shift() );
92-
}
88+
firing = false;
89+
90+
// Clean up if we're done firing for good
91+
if ( locked ) {
9392

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

98-
// Else, disable
97+
// Otherwise, this object is spent
9998
} else {
100-
self.disable();
99+
list = "";
101100
}
102101
}
103102
},
103+
104104
// Actual Callbacks object
105105
self = {
106+
106107
// Add a callback or a collection of callbacks to the list
107108
add: function() {
108109
if ( list ) {
109-
// First, we save the current length
110-
var start = list.length;
110+
111+
// If we have memory from a past run, we should fire after adding
112+
if ( memory && !firing ) {
113+
firingIndex = list.length - 1;
114+
queue.push( memory );
115+
}
116+
111117
(function add( args ) {
112118
jQuery.each( args, function( _, arg ) {
113-
var type = jQuery.type( arg );
114-
if ( type === "function" ) {
119+
if ( jQuery.isFunction( arg ) ) {
115120
if ( !options.unique || !self.has( arg ) ) {
116121
list.push( arg );
117122
}
118-
} else if ( arg && arg.length && type !== "string" ) {
123+
} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
119124
// Inspect recursively
120125
add( arg );
121126
}
122127
});
123128
})( arguments );
124-
// Do we need to add the callbacks to the
125-
// current firing batch?
126-
if ( firing ) {
127-
firingLength = list.length;
128-
// With memory, if we're not firing then
129-
// we should call right away
130-
} else if ( memory ) {
131-
firingStart = start;
132-
fire( memory );
129+
130+
if ( memory && !firing ) {
131+
fire();
133132
}
134133
}
135134
return this;
136135
},
137136

138137
// Remove a callback from the list
139138
remove: function() {
140-
if ( list ) {
141-
jQuery.each( arguments, function( _, arg ) {
142-
var index;
143-
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
144-
list.splice( index, 1 );
145-
// Handle firing indexes
146-
if ( firing ) {
147-
if ( index <= firingLength ) {
148-
firingLength--;
149-
}
150-
if ( index <= firingIndex ) {
151-
firingIndex--;
152-
}
153-
}
139+
jQuery.each( arguments, function( _, arg ) {
140+
var index;
141+
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
142+
list.splice( index, 1 );
143+
144+
// Handle firing indexes
145+
if ( index <= firingIndex ) {
146+
firingIndex--;
154147
}
155-
});
156-
}
148+
}
149+
});
157150
return this;
158151
},
159152

160153
// Check if a given callback is in the list.
161154
// If no argument is given, return whether or not list has callbacks attached.
162155
has: function( fn ) {
163-
return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
156+
return fn ?
157+
jQuery.inArray( fn, list ) > -1 :
158+
list.length > 0;
164159
},
165160

166161
// Remove all callbacks from the list
167162
empty: function() {
168163
if ( list ) {
169164
list = [];
170-
firingLength = 0;
171165
}
172166
return this;
173167
},
@@ -176,8 +170,8 @@ jQuery.Callbacks = function( options ) {
176170
// Abort any current/pending executions
177171
// Clear all callbacks and values
178172
disable: function() {
179-
list = stack = memory = undefined;
180-
locked = true;
173+
locked = queue = [];
174+
list = memory = "";
181175
return this;
182176
},
183177
disabled: function() {
@@ -188,10 +182,9 @@ jQuery.Callbacks = function( options ) {
188182
// Also disable .add unless we have memory (since it would have no effect)
189183
// Abort any pending executions
190184
lock: function() {
191-
stack = undefined;
192-
locked = true;
185+
locked = queue = [];
193186
if ( !memory && !firing ) {
194-
self.disable();
187+
list = memory = "";
195188
}
196189
return this;
197190
},
@@ -204,10 +197,9 @@ jQuery.Callbacks = function( options ) {
204197
if ( !locked ) {
205198
args = args || [];
206199
args = [ context, args.slice ? args.slice() : args ];
207-
if ( firing ) {
208-
stack.push( args );
209-
} else {
210-
fire( args );
200+
queue.push( args );
201+
if ( !firing ) {
202+
fire();
211203
}
212204
}
213205
return this;

0 commit comments

Comments
 (0)