Skip to content

Commit 2a7a07f

Browse files
committed
lib: prefer iterable weak set than WeakRefs in AbortSignal.any
1 parent d64835f commit 2a7a07f

File tree

1 file changed

+43
-14
lines changed

1 file changed

+43
-14
lines changed

lib/internal/abort_controller.js

+43-14
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)