| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -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 | |
| 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