Skip to content

Commit bdcc36b

Browse files
committed
lib: prefer iterable weak set than WeakRefs in AbortSignal.any
The dom spec specified "weak sets" for dependent and source signals. This was not captured due to the early implementation of AbortSignal.any prior to the spec PR getting landed. This commit fixes that behaviour, which could save us from WeakRef and deref everytime for these siganls.
1 parent d64835f commit bdcc36b

File tree

1 file changed

+43
-14
lines changed

1 file changed

+43
-14
lines changed

lib/internal/abort_controller.js

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44
// in https://github.com/mysticatea/abort-controller (MIT license)
55

66
const {
7+
ArrayPrototypePush,
78
ObjectAssign,
89
ObjectDefineProperties,
910
ObjectDefineProperty,
1011
PromiseResolve,
1112
SafeFinalizationRegistry,
1213
SafeSet,
1314
SafeWeakRef,
15+
SafeWeakSet,
1416
Symbol,
1517
SymbolToStringTag,
18+
WeakRefPrototypeDeref,
19+
WeakSetPrototypeAdd,
20+
WeakSetPrototypeHas,
1621
} = primordials;
1722

1823
const {
@@ -100,6 +105,33 @@ const kComposite = Symbol('kComposite');
100105
const kSourceSignals = Symbol('kSourceSignals');
101106
const kDependantSignals = Symbol('kDependantSignals');
102107

108+
// Since WeakSet is not iterable, we must use another iterable
109+
// data structure to make it "iterable".
110+
class IterableWeakSet {
111+
#weakSet = new SafeWeakSet();
112+
#weakRefs = [];
113+
114+
add(value) {
115+
if (!this.has(value)) {
116+
WeakSetPrototypeAdd(this.#weakSet, value);
117+
ArrayPrototypePush(this.#weakRefs, new SafeWeakRef(value));
118+
}
119+
}
120+
121+
has(value) {
122+
return WeakSetPrototypeHas(this.#weakSet, value);
123+
}
124+
125+
getIterable() {
126+
const iterable = [];
127+
for (let i = 0; i < this.#weakRefs.length; i++) {
128+
const item = WeakRefPrototypeDeref(this.#weakRefs[i]);
129+
ArrayPrototypePush(iterable, item);
130+
}
131+
return iterable;
132+
}
133+
}
134+
103135
function customInspect(self, obj, depth, options) {
104136
if (depth < 0)
105137
return self;
@@ -238,34 +270,32 @@ class AbortSignal extends EventTarget {
238270
if (!signalsArray.length) {
239271
return resultSignal;
240272
}
241-
const resultSignalWeakRef = new SafeWeakRef(resultSignal);
242-
resultSignal[kSourceSignals] = new SafeSet();
273+
resultSignal[kSourceSignals] = new IterableWeakSet();
243274
for (let i = 0; i < signalsArray.length; i++) {
244275
const signal = signalsArray[i];
245276
if (signal.aborted) {
246277
abortSignal(resultSignal, signal.reason);
247278
return resultSignal;
248279
}
249-
signal[kDependantSignals] ??= new SafeSet();
280+
signal[kDependantSignals] ??= new IterableWeakSet();
250281
if (!signal[kComposite]) {
251-
resultSignal[kSourceSignals].add(new SafeWeakRef(signal));
252-
signal[kDependantSignals].add(resultSignalWeakRef);
282+
resultSignal[kSourceSignals].add(signal);
283+
signal[kDependantSignals].add(resultSignal);
253284
} else if (!signal[kSourceSignals]) {
254285
continue;
255286
} else {
256-
for (const sourceSignal of signal[kSourceSignals]) {
257-
const sourceSignalRef = sourceSignal.deref();
258-
if (!sourceSignalRef) {
287+
for (const sourceSignal of signal[kSourceSignals].getIterable()) {
288+
if (!sourceSignal) {
259289
continue;
260290
}
261-
assert(!sourceSignalRef.aborted);
262-
assert(!sourceSignalRef[kComposite]);
291+
assert(!sourceSignal.aborted);
292+
assert(!sourceSignal[kComposite]);
263293

264294
if (resultSignal[kSourceSignals].has(sourceSignal)) {
265295
continue;
266296
}
267297
resultSignal[kSourceSignals].add(sourceSignal);
268-
sourceSignalRef[kDependantSignals].add(resultSignalWeakRef);
298+
sourceSignal[kDependantSignals].add(resultSignal);
269299
}
270300
}
271301
}
@@ -380,9 +410,8 @@ function abortSignal(signal, reason) {
380410
[kTrustEvent]: true,
381411
});
382412
signal.dispatchEvent(event);
383-
signal[kDependantSignals]?.forEach((s) => {
384-
const signalRef = s.deref();
385-
if (signalRef) abortSignal(signalRef, reason);
413+
signal[kDependantSignals]?.getIterable()?.forEach((s) => {
414+
if (s) abortSignal(s, reason);
386415
});
387416
}
388417

0 commit comments

Comments
 (0)