| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -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 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,28 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + require('../common'); | ||
| 4 | + const assert = require('assert'); | ||
| 5 | + const { once } = require('node:events'); | ||
| 6 | + const { describe, it } = require('node:test'); | ||
| 7 | + | ||
| 8 | + describe('AbortSignal.any() with timeout signals', () => { | ||
| 9 | + it('should abort when the first timeout signal fires', async () => { | ||
| 10 | + const signal = AbortSignal.any([AbortSignal.timeout(9000), AbortSignal.timeout(110000)]); | ||
| 11 | + | ||
| 12 | + const abortPromise = Promise.race([ | ||
| 13 | + once(signal, 'abort').then(() => { | ||
| 14 | + throw signal.reason; | ||
| 15 | + }), | ||
| 16 | + new Promise((resolve) => setTimeout(resolve, 10000)), | ||
| 17 | + ]); | ||
| 18 | + | ||
| 19 | + // The promise should be aborted by the 9000ms timeout | ||
| 20 | + await assert.rejects( | ||
| 21 | + () => abortPromise, | ||
| 22 | + { | ||
| 23 | + name: 'TimeoutError', | ||
| 24 | + message: 'The operation was aborted due to timeout' | ||
| 25 | + } | ||
| 26 | + ); | ||
| 27 | + }); | ||
| 28 | + }); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments