1
1
import type { EventData , ListenerEntry , Observable } from '../observable/index' ;
2
- import type { ViewBase } from '../../ui/core/view-base' ;
3
2
import { MutationSensitiveArray } from '../mutation-sensitive-array' ;
4
3
5
4
// This file contains some of Core's hot paths, so attention has been taken to
@@ -16,6 +15,13 @@ const timeOrigin = Date.now();
16
15
*/
17
16
const emptyArray = new MutationSensitiveArray < ListenerEntry > ( ) ;
18
17
18
+ /**
19
+ * Recycling the event path array rather than allocating a new one each time
20
+ * saves about 210 nanoseconds per dispatchTo() call (and avoids memory pressure
21
+ * and GC).
22
+ */
23
+ const recycledEventPath : Observable [ ] = [ ] ;
24
+
19
25
export class DOMEvent implements Event {
20
26
/**
21
27
* @private
@@ -157,7 +163,7 @@ export class DOMEvent implements Event {
157
163
158
164
// Walk up the target's parents if it has parents (is a ViewBase or
159
165
// subclass of ViewBase) or not (is an Observable).
160
- return this . target . isViewBase ( ) ? this . getEventPath ( this . target , 'bubble' ) : [ this . target ] ;
166
+ return [ ... this . getEventPath ( this . target , 'bubble' ) ] ;
161
167
}
162
168
163
169
/**
@@ -170,17 +176,23 @@ export class DOMEvent implements Event {
170
176
* @example
171
177
* [Button, StackLayout, Page] // 'bubble'
172
178
*/
173
- private getEventPath ( responder : ViewBase , path : 'capture' | 'bubble' ) : ViewBase [ ] {
174
- const chain = [ responder ] ;
179
+ private getEventPath ( responder : Observable , path : 'capture' | 'bubble' ) : Observable [ ] {
180
+ recycledEventPath . splice ( 0 , recycledEventPath . length ) ;
181
+ recycledEventPath . push ( responder ) ;
182
+
183
+ if ( ! responder . isViewBase ( ) ) {
184
+ return recycledEventPath ;
185
+ }
186
+
175
187
let nextResponder = responder . parent ;
176
188
while ( nextResponder ) {
177
- path === 'capture' ? chain . unshift ( nextResponder ) : chain . push ( nextResponder ) ;
189
+ path === 'capture' ? recycledEventPath . unshift ( nextResponder ) : recycledEventPath . push ( nextResponder ) ;
178
190
179
191
// TODO: decide whether to walk up from Page to Frame, and whether
180
192
// to then walk from Frame to Application or something.
181
193
nextResponder = nextResponder ?. parent ;
182
194
}
183
- return chain ;
195
+ return recycledEventPath ;
184
196
}
185
197
186
198
/** @deprecated */
@@ -278,7 +290,7 @@ export class DOMEvent implements Event {
278
290
phase : this . CAPTURING_PHASE ,
279
291
} ) ;
280
292
281
- const eventPath = target . isViewBase ( ) ? this . getEventPath ( target , 'capture' ) : [ target ] ;
293
+ const eventPath = this . getEventPath ( target , 'capture' ) ;
282
294
283
295
// Capturing phase, e.g. [Page, StackLayout, Button]
284
296
for ( const currentTarget of eventPath ) {
0 commit comments