Skip to content

Commit 4a15ce9

Browse files
committed
lib: propagate aborted state to dependent signals before firing events
1 parent 53ede87 commit 4a15ce9

1 file changed

Lines changed: 34 additions & 4 deletions

File tree

lib/internal/abort_controller.js

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

66
const {
7+
ArrayPrototypePush,
78
ObjectAssign,
89
ObjectDefineProperties,
910
ObjectDefineProperty,
11+
ObjectSetPrototypeOf,
1012
PromiseResolve,
1113
SafeFinalizationRegistry,
1214
SafeSet,
@@ -372,18 +374,46 @@ ObjectDefineProperty(AbortSignal.prototype, SymbolToStringTag, {
372374

373375
defineEventHandler(AbortSignal.prototype, 'abort');
374376

377+
// https://dom.spec.whatwg.org/#dom-abortsignal-abort
375378
function abortSignal(signal, reason) {
379+
// 1. If signal is aborted, then return.
376380
if (signal[kAborted]) return;
381+
382+
// 2. Set signal's abort reason to reason if it is given;
383+
// otherwise to a new "AbortError" DOMException.
377384
signal[kAborted] = true;
378385
signal[kReason] = reason;
386+
// 3. Let dependentSignalsToAbort be a new list.
387+
const dependentSignalsToAbort = ObjectSetPrototypeOf([], null);
388+
// 4. For each dependentSignal of signal's dependent signals:
389+
signal[kDependantSignals]?.forEach((s) => {
390+
const dependentSignal = s.deref();
391+
// 1. If dependentSignal is not aborted, then:
392+
if (dependentSignal && !dependentSignal[kAborted]) {
393+
// 1. Set dependentSignal's abort reason to signal's abort reason.
394+
dependentSignal[kReason] = reason;
395+
dependentSignal[kAborted] = true;
396+
// 2. Append dependentSignal to dependentSignalsToAbort.
397+
ArrayPrototypePush(dependentSignalsToAbort, dependentSignal);
398+
}
399+
});
400+
401+
// 5. Run the abort steps for signal
402+
runAbort(signal);
403+
// 6. For each dependentSignal of dependentSignalsToAbort,
404+
// run the abort steps for dependentSignal.
405+
for (let i = 0; i < dependentSignalsToAbort.length; i++) {
406+
const dependentSignal = dependentSignalsToAbort[i];
407+
runAbort(dependentSignal);
408+
}
409+
}
410+
411+
// To run the abort steps for an AbortSignal signal
412+
function runAbort(signal) {
379413
const event = new Event('abort', {
380414
[kTrustEvent]: true,
381415
});
382416
signal.dispatchEvent(event);
383-
signal[kDependantSignals]?.forEach((s) => {
384-
const signalRef = s.deref();
385-
if (signalRef) abortSignal(signalRef, reason);
386-
});
387417
}
388418

389419
class AbortController {

0 commit comments

Comments
 (0)