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