From d0a05700e4ba0ef7f419aade22258c5e34e2dbe9 Mon Sep 17 00:00:00 2001 From: Vitaly Tomilov Date: Sat, 3 Aug 2024 16:26:56 +0100 Subject: [PATCH] refactoring timeout + tests --- src/ops/async/delay.ts | 7 ++++++- src/ops/timeout.ts | 16 +++++++-------- test/ops/timeout/async.ts | 42 +++++++++++++++++++++++++++++---------- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/ops/async/delay.ts b/src/ops/async/delay.ts index e8f99ec0..2e66df35 100644 --- a/src/ops/async/delay.ts +++ b/src/ops/async/delay.ts @@ -2,7 +2,7 @@ import {$A, Operation, IterationState} from '../../types'; import {createOperation, throwOnSync} from '../../utils'; /** - * Delays each value by the specified timeout. + * Delays each value by the specified timeout (including the first one). * When the timeout is a negative number, no delay added. * * ```ts @@ -20,6 +20,11 @@ import {createOperation, throwOnSync} from '../../utils'; * } * ``` * + * Note that passing in `timeout = 0`, or returning the same from the callback, + * still uses the `timeout` function, just like `setTimeout(0)`, which can be used + * for throttling. In order to fully deactivate it, you need to pass in a negative + * `timeout` value. + * * @throws `Error: 'Operator "delay" requires asynchronous pipeline'` when used inside a synchronous pipeline. * * @see diff --git a/src/ops/timeout.ts b/src/ops/timeout.ts index eac0ceed..fc58e6cb 100644 --- a/src/ops/timeout.ts +++ b/src/ops/timeout.ts @@ -76,13 +76,13 @@ function timeoutSync( ms: number, cb?: (count: number) => void ): Iterable { + if (ms < 0) { + // timeout is inactive, reuse the source iterable instead: + return iterable; + } return { [$S](): Iterator { const i = iterable[$S](); - if (ms < 0) { - // timeout is inactive; - return i; - } let count = 0; // number of items processed let start: number; let done = false; @@ -113,13 +113,13 @@ function timeoutAsync( ms: number, cb?: (index: number) => void ): AsyncIterable { + if (ms < 0) { + // timeout is inactive, reuse the source iterable instead: + return iterable; + } return { [$A](): AsyncIterator { const i = iterable[$A](); - if (ms < 0) { - // timeout is inactive; - return i; - } let count = 0; // number of items processed let done = false; const resolutions: ((res: IteratorResult) => void)[] = []; diff --git a/test/ops/timeout/async.ts b/test/ops/timeout/async.ts index 2f50268a..5e51eb80 100644 --- a/test/ops/timeout/async.ts +++ b/test/ops/timeout/async.ts @@ -1,29 +1,36 @@ import {_asyncValues, expect} from '../../header'; -import {pipeAsync, delay, timeout, tap} from '../../../src'; +import { + pipeAsync, + delay, + timeout, + tap, + IterationState, + Operation +} from '../../../src'; export default () => { it('must end iteration after timeout', async () => { - const i = pipeAsync([1, 2, 3], delay(10), timeout(35)); + const i = pipeAsync([1, 2, 3], interval(10), timeout(19)); expect(await _asyncValues(i)).to.eql([1, 2]); }); it('must emit nothing when timeout does not permit', async () => { let count: any; const i = pipeAsync( - [1, 2, 3], - delay(10), - timeout(1, (c) => { + [11, 22, 33], + interval(10), + timeout(3, (c) => { count = c; }) ); - expect(await _asyncValues(i)).to.eql([]); - expect(count).to.eql(0); + expect(await _asyncValues(i)).to.eql([11]); + expect(count).to.eql(1); }); it('must invoke callback on timeout', async () => { let count; const i = pipeAsync( [1, 2, 3], - delay(10), - timeout(29, (c) => { + interval(10), + timeout(19, (c) => { count = c; }) ); @@ -49,7 +56,7 @@ export default () => { let e: any; const i = pipeAsync( [1, 2, 3], - delay(10), + interval(10), timeout(1, () => { throw new Error('timeout'); }) @@ -80,3 +87,18 @@ export default () => { expect(count).to.be.undefined; }); }; + +/** + * Helper borrowed from iter-ops-extras, to avoid delaying first value in tests; + * https://github.com/vitaly-t/iter-ops-extras/blob/main/src/interval.ts + */ +function interval( + timeout: + | number + | ((value: T, index: number, state: IterationState) => number) +): Operation { + if (typeof timeout === 'function') { + return delay((v, i, s) => (i ? timeout(v, i, s) : -1)); + } + return delay((_, i) => (i ? timeout : -1)); +}