Skip to content

Commit 58dfff8

Browse files
committed
perf(napi/parser): raw deser: remove WeakMap from NodeArray (#11868)
Improve the performance of `NodeArray` by removing the `WeakMap` which was used to get the inner `NodeArray` from a proxy. Use a private `Symbol` instead to perform the same function.
1 parent 54f9464 commit 58dfff8

File tree

1 file changed

+19
-18
lines changed

1 file changed

+19
-18
lines changed

napi/parser/raw-transfer/node-array.js

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
const { TOKEN, constructorError } = require('./lazy-common.js');
44

5-
// Mapping from a proxy to the `NodeArray` that it wraps.
6-
// Used by `slice`, `values`, `key` and `elements` methods.
5+
// Internal symbol to get `NodeArray` from a proxy wrapping a `NodeArray`.
76
//
8-
// TODO: Is there any way to avoid this?
9-
// Seems necessary because `this` in methods is a proxy, so accessing `this.#internal` throws.
10-
const nodeArrays = new WeakMap();
7+
// Methods of `NodeArray` are called with `this` being the proxy, rather than the `NodeArray` itself.
8+
// They can "unwrap" the proxy by getting `this[ARRAY]`, and the `get` proxy trap will return
9+
// the actual `NodeArray`.
10+
//
11+
// This symbol is not exported, and it is not actually defined on `NodeArray`s, so user cannot obtain it
12+
// via `Object.getOwnPropertySymbols` or `Reflect.ownKeys`. Therefore user code cannot unwrap the proxy.
13+
const ARRAY = Symbol();
1114

1215
// Function to get element from an array. Initialized in class static block below.
1316
let getElement;
@@ -43,10 +46,7 @@ class NodeArray extends Array {
4346

4447
super(length);
4548
this.#internal = { pos, ast, stride, construct };
46-
47-
const proxy = new Proxy(this, PROXY_HANDLERS);
48-
nodeArrays.set(proxy, this);
49-
return proxy;
49+
return new Proxy(this, PROXY_HANDLERS);
5050
}
5151

5252
// Allow `arr.filter`, `arr.map` etc.
@@ -56,25 +56,22 @@ class NodeArray extends Array {
5656
// TODO: Benchmark to check that this is actually faster.
5757
values() {
5858
// Get actual `NodeArray`. `this` is a proxy.
59-
const arr = nodeArrays.get(this);
59+
const arr = this[ARRAY];
6060
return new NodeArrayValuesIterator(arr.#internal, arr.length);
6161
}
6262

6363
// Override `keys` method with a more efficient one that avoids going via proxy for every iteration.
6464
// TODO: Benchmark to check that this is actually faster.
6565
keys() {
66-
// Get actual `NodeArray`. `this` is a proxy.
67-
// TODO: `this.length` would work here.
68-
// Not sure which is more expensive - property lookup via proxy, or `WeakMap` lookup.
69-
const arr = nodeArrays.get(this);
70-
return new NodeArrayKeysIterator(arr.length);
66+
// `this` is a proxy, but proxy will pass through getting `this.length` to the underlying `NodeArray`
67+
return new NodeArrayKeysIterator(this.length);
7168
}
7269

7370
// Override `entries` method with a more efficient one that avoids going via proxy for every iteration.
7471
// TODO: Benchmark to check that this is actually faster.
7572
entries() {
7673
// Get actual `NodeArray`. `this` is a proxy.
77-
const arr = nodeArrays.get(this);
74+
const arr = this[ARRAY];
7875
return new NodeArrayEntriesIterator(arr.#internal, arr.length);
7976
}
8077

@@ -92,8 +89,7 @@ class NodeArray extends Array {
9289
*/
9390
slice(start, end) {
9491
// Get actual `NodeArray`. `this` is a proxy.
95-
const arr = nodeArrays.get(this);
96-
if (arr === void 0) throw new Error('`slice` called on a value which is not a `NodeArray`');
92+
const arr = this[ARRAY];
9793

9894
start = toInt(start);
9995
if (start < 0) {
@@ -262,11 +258,16 @@ const PROXY_HANDLERS = {
262258

263259
// Get entries which are in bounds.
264260
get(arr, key) {
261+
// Methods of `NodeArray` are called with `this` being the proxy, rather than the `NodeArray` itself.
262+
// They can "unwrap" the proxy by getting `this[ARRAY]`.
263+
if (key === ARRAY) return arr;
264+
265265
if (isIndex(key)) {
266266
key *= 1;
267267
if (key >= arr.length) return void 0;
268268
return getElement(arr, key);
269269
}
270+
270271
return Reflect.get(arr, key);
271272
},
272273

0 commit comments

Comments
 (0)