|
1 | 1 | 'use strict'; |
2 | 2 |
|
3 | 3 | const { |
4 | | - ArrayPrototypeAt, |
5 | 4 | ArrayPrototypeForEach, |
6 | 5 | ArrayPrototypeIncludes, |
7 | 6 | DatePrototypeGetTime, |
@@ -14,9 +13,8 @@ const { |
14 | 13 | ObjectDefineProperty, |
15 | 14 | ObjectGetOwnPropertyDescriptor, |
16 | 15 | ObjectGetOwnPropertyDescriptors, |
17 | | - Promise, |
| 16 | + PromiseWithResolvers, |
18 | 17 | Symbol, |
19 | | - SymbolAsyncIterator, |
20 | 18 | SymbolDispose, |
21 | 19 | globalThis, |
22 | 20 | } = primordials; |
@@ -35,14 +33,15 @@ const { |
35 | 33 | }, |
36 | 34 | } = require('internal/errors'); |
37 | 35 |
|
| 36 | +const { addAbortListener } = require('internal/events/abort_listener'); |
| 37 | + |
38 | 38 | const { TIMEOUT_MAX } = require('internal/timers'); |
39 | 39 |
|
40 | 40 | const PriorityQueue = require('internal/priority_queue'); |
41 | 41 | const nodeTimers = require('timers'); |
42 | 42 | const nodeTimersPromises = require('timers/promises'); |
43 | 43 | const EventEmitter = require('events'); |
44 | 44 |
|
45 | | -let kResistStopPropagation; |
46 | 45 | // Internal reference to the MockTimers class inside MockDate |
47 | 46 | let kMock; |
48 | 47 | // Initial epoch to which #now should be set to |
@@ -423,62 +422,36 @@ class MockTimers { |
423 | 422 | } |
424 | 423 |
|
425 | 424 | async * #setIntervalPromisified(interval, result, options) { |
426 | | - const context = this; |
427 | 425 | const emitter = new EventEmitter(); |
| 426 | + |
| 427 | + let abortListener; |
428 | 428 | if (options?.signal) { |
429 | 429 | validateAbortSignal(options.signal, 'options.signal'); |
430 | 430 |
|
431 | 431 | if (options.signal.aborted) { |
432 | 432 | throw abortIt(options.signal); |
433 | 433 | } |
434 | 434 |
|
435 | | - const onAbort = (reason) => { |
436 | | - emitter.emit('data', { __proto__: null, aborted: true, reason }); |
437 | | - }; |
438 | | - |
439 | | - kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; |
440 | | - options.signal.addEventListener('abort', onAbort, { |
441 | | - __proto__: null, |
442 | | - once: true, |
443 | | - [kResistStopPropagation]: true, |
| 435 | + abortListener = addAbortListener(options.signal, () => { |
| 436 | + emitter.emit('error', abortIt(options.signal)); |
444 | 437 | }); |
445 | 438 | } |
446 | 439 |
|
447 | 440 | const eventIt = EventEmitter.on(emitter, 'data'); |
448 | | - const callback = () => { |
449 | | - emitter.emit('data', result); |
450 | | - }; |
| 441 | + const timer = this.#createTimer(true, |
| 442 | + () => emitter.emit('data'), |
| 443 | + interval, |
| 444 | + options); |
451 | 445 |
|
452 | | - const timer = this.#createTimer(true, callback, interval, options); |
453 | | - const clearListeners = () => { |
454 | | - emitter.removeAllListeners(); |
455 | | - context.#clearTimer(timer); |
456 | | - }; |
457 | | - const iterator = { |
458 | | - __proto__: null, |
459 | | - [SymbolAsyncIterator]() { |
460 | | - return this; |
461 | | - }, |
462 | | - async next() { |
463 | | - const result = await eventIt.next(); |
464 | | - const value = ArrayPrototypeAt(result.value, 0); |
465 | | - if (value?.aborted) { |
466 | | - iterator.return(); |
467 | | - throw abortIt(options.signal); |
468 | | - } |
469 | | - |
470 | | - return { |
471 | | - __proto__: null, |
472 | | - done: result.done, |
473 | | - value, |
474 | | - }; |
475 | | - }, |
476 | | - async return() { |
477 | | - clearListeners(); |
478 | | - return eventIt.return(); |
479 | | - }, |
480 | | - }; |
481 | | - yield* iterator; |
| 446 | + try { |
| 447 | + // eslint-disable-next-line no-unused-vars |
| 448 | + for await (const event of eventIt) { |
| 449 | + yield result; |
| 450 | + } |
| 451 | + } finally { |
| 452 | + abortListener?.[SymbolDispose](); |
| 453 | + this.#clearInterval(timer); |
| 454 | + } |
482 | 455 | } |
483 | 456 |
|
484 | 457 | #setImmediate(callback, ...args) { |
@@ -490,38 +463,31 @@ class MockTimers { |
490 | 463 | ); |
491 | 464 | } |
492 | 465 |
|
493 | | - #promisifyTimer({ timerFn, clearFn, ms, result, options }) { |
494 | | - return new Promise((resolve, reject) => { |
495 | | - if (options?.signal) { |
496 | | - try { |
497 | | - validateAbortSignal(options.signal, 'options.signal'); |
498 | | - } catch (err) { |
499 | | - return reject(err); |
500 | | - } |
501 | | - |
502 | | - if (options.signal.aborted) { |
503 | | - return reject(abortIt(options.signal)); |
504 | | - } |
505 | | - } |
| 466 | + async #promisifyTimer({ timerFn, clearFn, ms, result, options }) { |
| 467 | + const { promise, resolve, reject } = PromiseWithResolvers(); |
| 468 | + |
| 469 | + let abortListener; |
| 470 | + if (options?.signal) { |
| 471 | + validateAbortSignal(options.signal, 'options.signal'); |
506 | 472 |
|
507 | | - const onabort = () => { |
508 | | - clearFn(timer); |
509 | | - return reject(abortIt(options.signal)); |
510 | | - }; |
511 | | - |
512 | | - const timer = timerFn(() => { |
513 | | - return resolve(result); |
514 | | - }, ms); |
515 | | - |
516 | | - if (options?.signal) { |
517 | | - kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; |
518 | | - options.signal.addEventListener('abort', onabort, { |
519 | | - __proto__: null, |
520 | | - once: true, |
521 | | - [kResistStopPropagation]: true, |
522 | | - }); |
| 473 | + if (options.signal.aborted) { |
| 474 | + throw abortIt(options.signal); |
523 | 475 | } |
524 | | - }); |
| 476 | + |
| 477 | + abortListener = addAbortListener(options.signal, () => { |
| 478 | + reject(abortIt(options.signal)); |
| 479 | + }); |
| 480 | + } |
| 481 | + |
| 482 | + const timer = timerFn(resolve, ms); |
| 483 | + |
| 484 | + try { |
| 485 | + await promise; |
| 486 | + return result; |
| 487 | + } finally { |
| 488 | + abortListener?.[SymbolDispose](); |
| 489 | + clearFn(timer); |
| 490 | + } |
525 | 491 | } |
526 | 492 |
|
527 | 493 | #setImmediatePromisified(result, options) { |
|