rx-xtra.loop
v0.0.3
Published
RxJS Loop Function
Downloads
7
Maintainers
Readme
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 at0
and 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
|RepeatConfig
Limits how many repetitions are possible, and possibly introduces a delay between repetitions. If nocount
is 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:
- If this is meant to run forever, make sure to include some delays or other asynchrony to keep it from taking over the stack.
- If this is not meant to run forever, put in some limits, e.g. a
count
parameter; 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
!