Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/fasiha/callbag-throttle
Throttle operator for callbags π
https://github.com/fasiha/callbag-throttle
Last synced: 3 months ago
JSON representation
Throttle operator for callbags π
- Host: GitHub
- URL: https://github.com/fasiha/callbag-throttle
- Owner: fasiha
- License: unlicense
- Created: 2018-03-09T01:07:36.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2023-04-23T18:08:43.000Z (over 1 year ago)
- Last Synced: 2024-10-23T13:41:52.032Z (3 months ago)
- Language: JavaScript
- Size: 33.2 KB
- Stars: 10
- Watchers: 2
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
- awesome-callbags - throttle
README
# callbag-throttle
Like RxJS' [`throttleTime`](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-throttleTime), this callbag operator transforms a pullable or listenable source into a listenable that enforces a fixed-time cooldown period. Any data that arrives during the quiet time is ignored.
(See [`callbag-lossless-throttle`](https://github.com/fasiha/callbag-lossless-throttle) for a lossless version that queues up arrivals during the cooldown quiet period. This repo originally implemented lossless throttling but was changed to match RxJS users' intuition.)
## Background
- [`callbag-basics`](https://github.com/staltz/callbag-basics) and links to articles therein
- [GitHub's search results for "callbag"](https://github.com/search?q=callbag&type=Repositories&utf8=%E2%9C%93)
- AndrΓ© Staltz's ["Why we need callbags"](https://staltz.com/why-we-need-callbags.html)## Installation
On the command line in your Node.js app, run
```
$ npm install --save callbag-throttle
```
Then load it via
```js
const throttle = require('callbag-throttle');
```## API
With `const throttle = require('callbag-throttle')`, insert the following operator between a source and a sink to make the source a throttled listenable, i.e., a source that enforces a delay (in milliseconds) between data:
```js
throttle(delayMilliseconds)
```
The termination signal from the original source is not throttled if the original source was listenable, i.e., a sink will be notified immediately of a listenable's termination. However, this is not the case for a pullable: a sink will be notified of a throttled pullable's termination only after the delay (since the pullable is asked for more data only after the cooldown quiet time expires; it's possible that a better design can obviate this caveat?).## Examples
All examples use the following setup code, and use Node's [`process.hrtime`](https://nodejs.org/api/process.html#process_process_hrtime_time):
```js
// SETUP CODE
const throttle = require('callbag-lossless-throttle');
const { fromIter, interval, take, pipe } = require('callbag-basics');
// Let's define a slightly different forEach that shows us when the source terminates:
const forEachWithFinal = operation => source => {
let talkback;
source(0, (t, d) => {
if (t === 0) talkback = d;
if (t === 1) operation(d);
if (t === 1 || t === 0) talkback(1);
if (t === 2) { operation("TERMINATED"); }
});
};
function elapsed(start) {
const end = process.hrtime(start);
return Math.round(end[0] * 1000 + end[1] / 1e6);
}
```If we gently throttle an already-slow listenable, the resulting callbag is indistinguishable from the unthrottled case:
```js
var tic = process.hrtime();
pipe(interval(100), take(5), forEachWithFinal(x => console.log(`${x}: ${elapsed(tic)} ms: original`)));
pipe(interval(100), take(5), throttle(90),
forEachWithFinal(x => console.log(`${x}: ${elapsed(tic)} ms: (not really) throttled`)));
// 0: 107 ms: original
// 0: 110 ms: (not really) throttled
// 1: 211 ms: original
// 1: 211 ms: (not really) throttled
// 2: 313 ms: original
// 2: 313 ms: (not really) throttled
// 3: 413 ms: original
// 3: 413 ms: (not really) throttled
// 4: 514 ms: original
// TERMINATED: 514 ms: original
// 4: 515 ms: (not really) throttled
// TERMINATED: 515 ms: (not really) throttled
```This next example shows real throttling: only three of five data points from the source are seen after throttling. This is a listenable example again:
```js
var tic = process.hrtime();
pipe(interval(100), take(5), forEach(x => console.log(`${x}: ${elapsed(tic)} ms: original`)));
pipe(interval(100), take(5), throttle(150), forEach(x => console.log(`${x}: ${elapsed(tic)} ms: throttled to 150 ms`)));
// 0: 102 ms: original
// 0: 105 ms: throttled to 150 ms
// 1: 206 ms: original
// 2: 306 ms: original
// 2: 306 ms: throttled to 150 ms
// 3: 408 ms: original
// 4: 513 ms: original
// TERMINATED: 513 ms: original
// 4: 513 ms: throttled to 150 ms
// TERMINATED: 514 ms: throttled to 150 ms
```
Notice how in both these examples, the original source's termination is passed on without delay.This is in contrast to a pullable source. After throttling, it becomes a listenable source, but the delay has to be applied between the last non-terminate data and the termination:
```js
var tic = process.hrtime();
pipe(fromIter([ 10, 20, 30, 40 ]), forEach(x => console.log(`${x}: ${elapsed(tic)} ms: original`)));
pipe(fromIter([ 10, 20, 30, 40 ]), throttle(50), forEach(x => console.log(`${x}: ${elapsed(tic)} ms: throttled`)));
// 10: 1 ms: original
// 20: 2 ms: original
// 30: 3 ms: original
// 40: 3 ms: original
// TERMINATED: 3 ms: original
// 10: 3 ms: throttled
// 20: 55 ms: throttled
// 30: 107 ms: throttled
// 40: 159 ms: throttled
// TERMINATED: 211 ms: throttled
```