@@ -259,14 +259,30 @@ class AbortSignal extends EventTarget {
259
259
if ( ! signalsArray . length ) {
260
260
return resultSignal ;
261
261
}
262
+
262
263
const resultSignalWeakRef = new SafeWeakRef ( resultSignal ) ;
263
264
resultSignal [ kSourceSignals ] = new SafeSet ( ) ;
265
+
266
+ // Track if we have any timeout signals
267
+ let hasTimeoutSignals = false ;
268
+
264
269
for ( let i = 0 ; i < signalsArray . length ; i ++ ) {
265
270
const signal = signalsArray [ i ] ;
271
+
272
+ // Check if this is a timeout signal
273
+ if ( signal [ kTimeout ] ) {
274
+ hasTimeoutSignals = true ;
275
+
276
+ // Add the timeout signal to gcPersistentSignals to keep it alive
277
+ // This is what the kNewListener method would do when adding abort listeners
278
+ gcPersistentSignals . add ( signal ) ;
279
+ }
280
+
266
281
if ( signal . aborted ) {
267
282
abortSignal ( resultSignal , signal . reason ) ;
268
283
return resultSignal ;
269
284
}
285
+
270
286
signal [ kDependantSignals ] ??= new SafeSet ( ) ;
271
287
if ( ! signal [ kComposite ] ) {
272
288
const signalWeakRef = new SafeWeakRef ( signal ) ;
@@ -301,6 +317,12 @@ class AbortSignal extends EventTarget {
301
317
}
302
318
}
303
319
}
320
+
321
+ // If we have any timeout signals, add the composite signal to gcPersistentSignals
322
+ if ( hasTimeoutSignals && resultSignal [ kSourceSignals ] . size > 0 ) {
323
+ gcPersistentSignals . add ( resultSignal ) ;
324
+ }
325
+
304
326
return resultSignal ;
305
327
}
306
328
@@ -416,8 +438,10 @@ function abortSignal(signal, reason) {
416
438
// otherwise to a new "AbortError" DOMException.
417
439
signal [ kAborted ] = true ;
418
440
signal [ kReason ] = reason ;
441
+
419
442
// 3. Let dependentSignalsToAbort be a new list.
420
443
const dependentSignalsToAbort = ObjectSetPrototypeOf ( [ ] , null ) ;
444
+
421
445
// 4. For each dependentSignal of signal's dependent signals:
422
446
signal [ kDependantSignals ] ?. forEach ( ( s ) => {
423
447
const dependentSignal = s . deref ( ) ;
@@ -433,12 +457,27 @@ function abortSignal(signal, reason) {
433
457
434
458
// 5. Run the abort steps for signal
435
459
runAbort ( signal ) ;
460
+
436
461
// 6. For each dependentSignal of dependentSignalsToAbort,
437
462
// run the abort steps for dependentSignal.
438
463
for ( let i = 0 ; i < dependentSignalsToAbort . length ; i ++ ) {
439
464
const dependentSignal = dependentSignalsToAbort [ i ] ;
440
465
runAbort ( dependentSignal ) ;
441
466
}
467
+
468
+ // Clean up the signal from gcPersistentSignals
469
+ gcPersistentSignals . delete ( signal ) ;
470
+
471
+ // If this is a composite signal, also remove all of its source signals from gcPersistentSignals
472
+ // when they get dereferenced from the signal's kSourceSignals set
473
+ if ( signal [ kComposite ] && signal [ kSourceSignals ] ) {
474
+ signal [ kSourceSignals ] . forEach ( ( sourceWeakRef ) => {
475
+ const sourceSignal = sourceWeakRef . deref ( ) ;
476
+ if ( sourceSignal ) {
477
+ gcPersistentSignals . delete ( sourceSignal ) ;
478
+ }
479
+ } ) ;
480
+ }
442
481
}
443
482
444
483
// To run the abort steps for an AbortSignal signal
0 commit comments