rx-xtra.loop v0.0.3
Rx Xtra: Loop
loop creates an RxJS Observable from a callback, calling it with an index so you know how many repetitions have already elapsed. It combines the lazy instantiation and coercion of defer with the repetition control of repeat.
loop is great when you want to repeat a process and know which repetition you're on. Paginated results is probably the best use case.
rx-xtra.loop is part of Rx Xtra, a collection of RxJS utilities.
Created by Joel Shinness LinkTree • Github • Buy me a coffee!
Usage
loop<T>
- Parameters
factory:(index:number) => ObservableInput<T>Accepts an index that starts at0and increments every repetition. Returns anObservableInput<T>, e.g. anObservable<T>, or anything that can be coerced into anObservable<T>, such as an Array, Promise, Iterable, or AsyncIterable.countOrConfig?:number|RepeatConfigLimits how many repetitions are possible, and possibly introduces a delay between repetitions. If nocountis specified, the output Observable will nevercomplete, though it mayerror.
- Returns
Loop provides a functionality similar to for(let i = 0; true; i++) in procedural JavaScript, creating an inner Observable from a factory function. The factory receives an index that starts from 0, then increments on each repetition. When the inner Observable is created, its next and error are fed to the outer Observable, but when it finishes, the loop is done, and a new Observable is generated by the factory.
If there is a RepeatConfig or number given as the second parameter, it can limit the number of repetitions.
NOTE: This operator has the potential to create a harmful infinite loop, so take the following advice: 1. If this is meant to run forever, make sure to include some delays or other asynchrony to keep it from taking over the stack. 2. If this is not meant to run forever, put in some limits, e.g. a
countparameter; using thetake, 'takeUntil ortakeWhile; or throwing anerror.
Observe the following diagram. If there is a factory function that produces the following Observables for the inputs 0, 1, and 2, ...

Then calling loop(factory) would produce this Observable:

If one of the inner Observables were to error out, then the output Observable would also error out.

Examples
import { loop } from 'rx-xtra.loop';
import { takeWhile } from 'rxjs/operators';
type DbRow = { /* Some Data Type */ }
async function getPageOfResults(pageStart:number, pageSize:number):Promise<DbRow[]>{
const { data } = await SqlQuery(`
SELECT *
FROM dbTable
SKIP ? LIMIT ?`,
[pageStart, pageSize]);
return data;
}
function getPages(pageSize:number){
return loop((index:number) => getPaginatedResults(index * pageSize, pageSize)).pipe(
takeWhile(results => results.length >= pageSize, true)
);
}See Also
- Got an Observable-like thing you want to "coerce" into a real Observable? Use
from! - Like being able to convert Observable-like things into real Observables, and like waiting until Subscription to do so, but you don't need the repetition aspect? Use
defer! - Have an existing Observable that you want to subscribe to over and over? Use
repeat! - Like everything about
loop, but you don't need the index? Then you can combine the last two like this:defer(factory).pipe(repeat(countOrConfig)) - Like
loop, but you have some some state to pass between repetitions? Then take a look atrx-xtra.loop-scan!