8000 fix: recycle eventPath · NativeScript/NativeScript@66f62fb · GitHub
[go: up one dir, main page]

Skip to content

Commit 66f62fb

Browse files
committed
fix: recycle eventPath
1 parent efb1a93 commit 66f62fb

File tree

1 file changed

+19
-7
lines changed

1 file changed

+19
-7
lines changed

packages/core/data/dom-events/dom-event.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { EventData, ListenerEntry, Observable } from '../observable/index';
2-
import type { ViewBase } from '../../ui/core/view-base';
32
import { MutationSensitiveArray } from '../mutation-sensitive-array';
43

54
// This file contains some of Core's hot paths, so attention has been taken to
@@ -16,6 +15,13 @@ const timeOrigin = Date.now();
1615
*/
1716
const emptyArray = new MutationSensitiveArray<ListenerEntry>();
1817

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+
1925
export class DOMEvent implements Event {
2026
/**
2127
* @private
@@ -157,7 +163,7 @@ export class DOMEvent implements Event {
157163

158164
// Walk up the target's parents if it has parents (is a ViewBase or
159165
// 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')];
161167
}
162168

163169
/**
@@ -170,17 +176,23 @@ export class DOMEvent implements Event {
170176
* @example
171177
* [Button, StackLayout, Page] // 'bubble'
172178
*/
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+
175187
let nextResponder = responder.parent;
176188
while (nextResponder) {
177-
path === 'capture' ? chain.unshift(nextResponder) : chain.push(nextResponder);
189+
path === 'capture' ? recycledEventPath.unshift(nextResponder) : recycledEventPath.push(nextResponder);
178190

179191
// TODO: decide whether to walk up from Page to Frame, and whether
180192
// to then walk from Frame to Application or something.
181193
nextResponder = nextResponder?.parent;
182194
}
183-
return chain;
195+
return recycledEventPath;
184196
}
185197

186198
/** @deprecated */
@@ -278,7 +290,7 @@ export class DOMEvent implements Event {
278290
phase: this.CAPTURING_PHASE,
279291
});
280292

281-
const eventPath = target.isViewBase() ? this.getEventPath(target, 'capture') : [target];
293+
const eventPath = this.getEventPath(target, 'capture');
282294

283295
// Capturing phase, e.g. [Page, StackLayout, Button]
284296
for (const currentTarget of eventPath) {

0 commit comments

Comments
 (0)
0