UNPKG

ix

Version:

The Interactive Extensions for JavaScript

96 lines (87 loc) 2.7 kB
import { AsyncIterableX } from '../asynciterablex.js'; import { MonoTypeOperatorAsyncFunction } from '../../interfaces.js'; import { AbortError, throwIfAborted } from '../../aborterror.js'; /** @ignore */ export class DebounceAsyncIterable<TSource> extends AsyncIterableX<TSource> { private _source: AsyncIterable<TSource>; private _time: number; constructor(source: AsyncIterable<TSource>, time: number) { super(); this._source = source; this._time = time; } async *[Symbol.asyncIterator](signal?: AbortSignal) { throwIfAborted(signal); let done = false; let reject: (reason?: any) => void = () => { /**/ }; let resolve: (value: TSource | PromiseLike<TSource>) => void = () => { /**/ }; let promise = new Promise<TSource>((r1, r2) => { resolve = r1; reject = r2; }); (async () => { let id: any = null; const emitValue = (value: TSource) => { id = null; resolve(value); promise = new Promise<TSource>((r1, r2) => { resolve = r1; reject = r2; }); }; if (signal) { signal.addEventListener( 'abort', () => { done = true; if (id) { clearTimeout(id); } id = null; reject(new AbortError()); }, { once: true } ); } try { let result: IteratorResult<TSource>; // @ts-ignore const it = this._source[Symbol.asyncIterator](signal); // 1. check `!done` // 2. await next value // 3. check `!done` again, in case the signal aborted while the promise was pending while (!done && !(result = await it.next()).done && !done) { if (id) { clearTimeout(id); } id = setTimeout(emitValue, this._time, result.value); } } catch (e) { reject(e); } done = true; })(); while (!done) { yield await promise; } } } /** * Emits a notification from the source async-iterable only after a particular time span * has passed without another source emission. * * @template TSource The type of elements in the source sequence. * @param {number} time The timeout duration in milliseconds * @returns {MonoTypeOperatorAsyncFunction<TSource>} An operator function which debounces by the given timeout. */ export function debounce<TSource>(time: number): MonoTypeOperatorAsyncFunction<TSource> { return function debounceOperatorFunction( source: AsyncIterable<TSource> ): AsyncIterableX<TSource> { return new DebounceAsyncIterable<TSource>(source, time); }; }