UNPKG

@bemedev/rx-add-ons

Version:

A collection of RxJS operators and utilities to enhance reactive programming capabilities.

130 lines (127 loc) 4.42 kB
import { EMPTY, Observable } from 'rxjs'; import { race } from 'rxjs/internal/observable/race'; import { timer } from 'rxjs/internal/observable/timer'; import { switchMap } from 'rxjs/internal/operators/switchMap'; /** * Switches to a fallback Observable if the source doesn't emit within the specified timeout. * Unlike the standard timeout operator, this doesn't error but switches to the fallback. * * @param timeout - Timeout duration in milliseconds * @param fallback - Observable to switch to on timeout * @returns A function that returns an Observable that emits from source or fallback * * @example * ```typescript * // Switch to fallback after 5 seconds * source$.pipe( * timeoutWithFallback(5000, of('timeout')) * ) * * // Switch to alternative data source on timeout * source$.pipe( * timeoutWithFallback(3000, alternativeSource$) * ) * ``` */ const timeoutWithFallback = (timeout, fallback = EMPTY) => { return source => { return race(source, timer(timeout).pipe(switchMap(() => fallback))); }; }; /** * Switches to a fallback Observable if the source doesn't emit within the specified timeout. * Unlike the standard timeout operator, this doesn't error but switches to the fallback. * * @param timeout - Timeout duration in milliseconds * @param fallback - Observable to switch to on timeout * @returns A function that returns an Observable that emits from source or fallback * * @example * ```typescript * // Switch to fallback after 5 seconds * source$.pipe( * timeoutWithFallback(5000, of('timeout')) * ) * * // Switch to alternative data source on timeout * source$.pipe( * timeoutWithFallback(3000, alternativeSource$) * ) * ``` */ const timeout = timeoutWithFallback; /** * Timeout with fallback that can be configured per emission * Resets timeout on each emission from source * * @see {@linkcode timeoutWithFallback} */ const tickWithFallback = (timeout, fallback = EMPTY) => { return source => { return new Observable(subscriber => { let timeoutHandle = null; let isCompleted = false; const resetTimeout = () => { if (timeoutHandle) { clearTimeout(timeoutHandle); } timeoutHandle = setTimeout(() => { if (!isCompleted) { isCompleted = true; sourceSubscription.unsubscribe(); // Switch to fallback fallback.subscribe({ next: value => subscriber.next(value), error: err => subscriber.error(err), complete: () => subscriber.complete(), }); } }, timeout); }; // Start initial timeout resetTimeout(); const sourceSubscription = source.subscribe({ next: value => { if (!isCompleted) { subscriber.next(value); resetTimeout(); // Reset timeout on each emission } }, error: err => { if (!isCompleted) { isCompleted = true; if (timeoutHandle) { clearTimeout(timeoutHandle); } subscriber.error(err); } }, complete: () => { if (!isCompleted) { isCompleted = true; if (timeoutHandle) { clearTimeout(timeoutHandle); } subscriber.complete(); } }, }); return () => { isCompleted = true; if (timeoutHandle) { clearTimeout(timeoutHandle); } sourceSubscription.unsubscribe(); }; }); }; }; /** * Timeout with fallback that can be configured per emission * Resets timeout on each emission from source * * @see {@linkcode timeoutWithFallback} */ const tick = tickWithFallback; export { tick, tickWithFallback, timeout, timeoutWithFallback }; //# sourceMappingURL=time.js.map