├── dummy.js
├── bufferWithCount.md
├── history.md
└── README.md
/dummy.js:
--------------------------------------------------------------------------------
1 | // Tells GitHub this repo is about JavaScript
2 |
--------------------------------------------------------------------------------
/bufferWithCount.md:
--------------------------------------------------------------------------------
1 | ### Buffer every N events and emit as single event
2 |
3 | ```js
4 | import Most from "most";
5 | import {add, append, curry, takeLast} from "ramda";
6 |
7 | // Number -> Stream a -> Stream [a]
8 | let buffer = curry((n, s$) => {
9 | return s$
10 | .loop((memo, item) => {
11 | let value = takeLast(n, append(item, memo));
12 | let seed = value.length == n ? [] : value;
13 | return {seed, value};
14 | }, [])
15 | .filter(x => x.length == n)
16 | });
17 |
18 | let s$ = Most
19 | .periodic(100, 1)
20 | .scan(add, 0); // 0--1--2--...
21 |
22 | buffer(3, s$) // [0, 1, 2]--[3, 4, 5]--...
23 | .observe(console.log);
24 | ```
25 |
--------------------------------------------------------------------------------
/history.md:
--------------------------------------------------------------------------------
1 | ### Track history for N events
2 |
3 | #### RxJS
4 |
5 | ```js
6 | let {append, drop, repeat} = require("ramda")
7 |
8 | let appendSliding = curry((n, x, xs) => {
9 | let ys = append(x, xs)
10 | if (ys.length > n) {
11 | return drop(ys.length - n, ys)
12 | } else {
13 | return ys
14 | }
15 | })
16 |
17 | let history = function (n) {
18 | if (n <= 0) {
19 | throw Error("n must be an unsigned integer, got "+ String(n))
20 | }
21 | let put = appendSliding(n)
22 | return this.scan((stateHistory, newState) => {
23 | return put(newState, stateHistory)
24 | }, repeat(null, n))
25 | }
26 |
27 | // Usage
28 | statefulStream
29 | ::history(3)
30 | ```
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Reactive polyglot
2 |
3 | **`R.`** [(Ramda)](http://ramdajs.com/0.19.1/index.html) stands for standard functional toolkit.
4 |
5 | ### Comparison notes
6 |
7 | Operator counterparts aren't and can't be fully equivalent.
8 | "Kinda the same" – is the current definition.
9 |
10 | The following projects, were created with different goals and tradeoffs in mind, so every comparison
11 | and analogy is subjective and can be argued. The presence of some operator is not necessary good, as
12 | well as the abscence is not necessary bad.
13 |
14 | Note, that primitives differ for each library. In descriptions, we broadly refer to all the "observable
15 | primitives" as **streams***, though, technically speaking, some of them are rather stream-like entities.
16 |
17 | To find something, search for a term you know.
18 |
19 | ## API
20 |
21 | ### Create
22 |
23 | #### Create an empty stream
24 |
25 | * KefirJS: [`never`](http://kefirjs.github.io/kefir/#never)
26 | * MostJS: [`empty`](https://github.com/cujojs/most/blob/master/docs/api.md#mostempty)
27 | * RxJS: [`of`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/of.md)
28 | * XStream: [`empty`](https://github.com/staltz/xstream#of)
29 |
30 | #### Create a stream from a single value
31 |
32 | * KefirJS: [`constant`](http://kefirjs.github.io/kefir/#constant)
33 | * MostJS: [`of`](https://github.com/cujojs/most/blob/master/docs/api.md#mostjust), [`just`](https://github.com/cujojs/most/blob/master/docs/api.md#mostjust)
34 | * RxJS: [`of`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/of.md), [`just`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/return.md)
35 | * XStream: [`of`](https://github.com/staltz/xstream#of)
36 |
37 | #### Create a stream from an array
38 |
39 | * KefirJS: [`sequentially`](http://kefirjs.github.io/kefir/#sequentially)
40 | * MostJS: [`from`](https://github.com/cujojs/most/blob/master/docs/api.md#mostfrom)
41 | * RxJS: [`from`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/from.md), [`of`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/of.md)
42 | * XStream: [`from`](https://github.com/staltz/xstream#from), [`fromArray`](https://github.com/staltz/xstream#fromArray)
43 |
44 | #### Create a stream from a promise
45 |
46 | * KefirJS: [`fromPromise`](http://kefirjs.github.io/kefir/#from-promise)
47 | * MostJS: [`fromPromise`](https://github.com/cujojs/most/blob/master/docs/api.md#mostfrompromise)
48 | * RxJS: [`fromPromise`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/frompromise.md)
49 | * XStream: [`fromPromise`](https://github.com/staltz/xstream#fromPromise)
50 |
51 | #### Create a stream from an event
52 |
53 | * KefirJS: [`fromEvents`](http://kefirjs.github.io/kefir/#from-event)
54 | * MostJS: [`fromEvent`](https://github.com/cujojs/most/blob/master/docs/api.md#mostfromevent)
55 | * RxJS: [`fromEvent`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/fromevent.md)
56 | * XStream: [`fromEvent`](https://github.com/staltz/xstream/blob/master/EXTRA_DOCS.md#fromEvent)
57 |
58 | #### Create a stream from a callback
59 |
60 | * KefirJS: [`stream`](http://kefirjs.github.io/kefir/#stream), [`fromCallback`](http://kefirjs.github.io/kefir/#from-callback), [`fromNodeCallback`](http://kefirjs.github.io/kefir/#from-node-callback), [`fromPoll`](http://kefirjs.github.io/kefir/#from-poll)
61 | * MostJS: `new Stream`
62 | * RxJS: `new Observable`, `bindCallback`, `bindNodeCallback`
63 | * XStream: `? (make a promise first)`
64 |
65 | #### Prepend a stream with a value
66 |
67 | * KefirJS: [`merge`](http://kefirjs.github.io/kefir/#merge) `+` [`constant`](http://kefirjs.github.io/kefir/#constant)
68 | * MostJS: `startWith`
69 | * RxJS: [`startWith`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/startwith.md)
70 | * XStream: `startWith`
71 |
72 | ### Transform (data events)
73 |
74 | #### Map value one-to-one
75 |
76 | * KefirJS: [`map`](http://kefirjs.github.io/kefir/#map)
77 | * MostJS: `map`, `constant`
78 | * RxJS: [`map`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/select.md), `mapTo`
79 | * XStream: `map`
80 |
81 | #### Filter value by a predicate
82 |
83 | * KefirJS: [`filter`](http://kefirjs.github.io/kefir/#filter)
84 | * MostJS: `filter`
85 | * RxJS: [`filter`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/where.md)
86 | * XStream: `filter`
87 |
88 | #### Skip N initial values
89 |
90 | * KefirJS: [`skip`](http://kefirjs.github.io/kefir/#skip)
91 | * MostJS: `skip`
92 | * RxJS: [`skip`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/skip.md)
93 | * XStream: `drop`
94 |
95 | #### Take N initial values
96 |
97 | * KefirJS: [`take`](http://kefirjs.github.io/kefir/#take)
98 | * MostJS: `take`
99 | * RxJS: [`take`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/take.md)
100 | * XStream: `take`
101 |
102 | #### Make a value from an accumulator and a next value
103 |
104 | * KefirJS: [`scan`](http://kefirjs.github.io/kefir/#scan)
105 | * MostJS: `scan`
106 | * RxJS: [`scan`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/scan.md)
107 | * XStream: `fold`
108 |
109 | ### Combine
110 |
111 | #### Merge multiple streams together
112 |
113 | * KefirJS: [`merge`](http://kefirjs.github.io/kefir/#merge)
114 | * MostJS: `merge`
115 | * RxJS: [`merge`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/merge.md)
116 | * XStream: `merge`
117 |
118 | Pay attention that Kefir's `merge` accepts arrays while others are variadic.
119 |
120 | #### Combine multiple streams together
121 |
122 | * KefirJS: [`combine`](http://kefirjs.github.io/kefir/#combine)
123 | * MostJS: `combine`
124 | * RxJS: [`combineLatest`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/combinelatest.md)
125 | * XStream: `combine`
126 |
127 | #### Sample a stream by another stream
128 |
129 | * KefirJS: [`combine`](http://kefirjs.github.io/kefir/#combine), [`sampledBy`](http://kefirjs.github.io/kefir/#obs-sampled-by)
130 | * MostJS: `sample`, `sampleWith`
131 | * RxJS: [`sample`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/sample.md), [`withLatestFrom`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/withlatestfrom.md)
132 | * XStream: `sampleCombine`
133 |
134 | #### Chain streams sequentially
135 |
136 | * KefirJS: [`flatMapConcat`](http://kefirjs.github.io/kefir/#flat-map-concat)
137 | * MostJS: [`concatMap`](https://github.com/cujojs/most/blob/master/docs/api.md#concatmap)
138 | * RxJS: [`concatMap`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/concatmap.md)
139 | * XStream: `map + flattenSequentially`
140 |
141 | ---
142 |
143 | ### Create
144 |
145 | Create stream from non-stream values.
146 |
147 |
148 |
149 | | KefirJS |
150 | MostJS |
151 | RxJS |
152 | XStream |
153 |
154 |
155 | interval |
156 | periodic |
157 | interval + map |
158 | periodic |
159 |
160 |
161 | repeat |
162 | of + R.range |
163 | repeat |
164 | of + R.range |
165 |
166 |
167 | ? |
168 | iterate |
169 | generate |
170 | ? |
171 |
172 |
173 | ? |
174 | generate |
175 | generate |
176 | ? |
177 |
178 |
179 |
180 | ### Mapper
181 |
182 | Modify events one to one.
183 |
184 |
185 |
186 | | KefirJS |
187 | MostJS |
188 | RxJS |
189 | XStream |
190 |
191 |
192 | delay |
193 | delay |
194 | delay |
195 | combine(delay(500)) |
196 |
197 |
198 | – (map) |
199 | timestamp |
200 | timestamp |
201 | – (map) |
202 |
203 |
204 |
205 | ### Transforms
206 |
207 | Modify events * to *.
208 |
209 |
210 |
211 | | MostJS |
212 | RxJS |
213 | XStream |
214 |
215 |
216 | chain / flatMap |
217 | flatMap |
218 | map + flattenConcurrently |
219 |
220 |
221 | map + switch |
222 | switchMap / flatMapLatest |
223 | map + flatten |
224 |
225 |
226 | join |
227 | mergeAll |
228 | flatten |
229 |
230 |
231 | loop |
232 | scan + map |
233 | fold + map |
234 |
235 |
236 | – (custom) |
237 | bufferWithCount |
238 | ? |
239 |
240 |
241 |
242 | ### Filters
243 |
244 | Skip events by predicate or signal.
245 |
246 |
247 |
248 | | MostJS |
249 | RxJS |
250 | XStream |
251 |
252 |
253 | skipRepeats |
254 | distinctUntilChanged |
255 | dropRepeats |
256 |
257 |
258 | skipRepeatsWith |
259 | – (scan) |
260 | dropRepeats |
261 |
262 |
263 | slice |
264 | skip + take |
265 | drop + take |
266 |
267 |
268 | skipWhile |
269 | skipWhile |
270 | fold + filter + map |
271 |
272 |
273 | takeWhile |
274 | takeWhile |
275 | filter + endWhen |
276 |
277 |
278 | since / skipUntil |
279 | skipUntil |
280 | fold + filter + map |
281 |
282 |
283 | until / takeUntil |
284 | takeUntil |
285 | filter + endWhen |
286 |
287 |
288 | during |
289 | window + take(1) |
290 | ? |
291 |
292 |
293 |
294 | ### Combinators
295 |
296 | Combine multiple streams into single.
297 |
298 |
299 |
300 | | MostJS |
301 | RxJS |
302 | XStream |
303 |
304 |
305 | zip |
306 | zip |
307 | ? |
308 |
309 |
310 | concat |
311 | concat |
312 | concat |
313 |
314 |
315 | ap |
316 | combineLatest |
317 | ? |
318 |
319 |
320 |
321 | ### Side effects
322 |
323 | Produce side effect for every event.
324 |
325 |
326 |
327 | | MostJS |
328 | RxJS |
329 | XStream |
330 |
331 |
332 | tap |
333 | do / tap |
334 | debug |
335 |
336 |
337 |
338 | ### Ending
339 |
340 | Operators which target **end** event somehow.
341 |
342 |
343 |
344 | | MostJS |
345 | RxJS |
346 | XStream |
347 |
348 |
349 | empty |
350 | empty |
351 | empty |
352 |
353 |
354 | never |
355 | never |
356 | never |
357 |
358 |
359 | continueWith |
360 | ? |
361 | concat |
362 |
363 |
364 |
365 | ### Concurrency
366 |
367 |
368 |
369 | | MostJS |
370 | RxJS |
371 |
372 |
373 | – (custom) |
374 | amb / race |
375 |
376 |
377 |
378 | ### History
379 |
380 |
381 |
382 | | MostJS |
383 | RxJS |
384 |
385 |
386 | – (custom) |
387 |
388 |
389 |
390 | ### Design diffs
391 |
392 | #### RxJS
393 |
394 | 1. Three primitives: `Observer`, `Observable`, `Subject`.
395 | 2. Observables end on error.
396 | 3. Provides API to handle errors.
397 | 3. Does not provide API to handle ending.
398 |
399 | #### KefirJS
400 |
401 | 1. Two primitives: `Stream` and `Property` (like XStream).
402 | 2. Observables does not end on error (by default).
403 | 3. Provides API to handle errors.
404 | 4. Provides API to handle ending.
405 |
406 | #### MostJS
407 |
408 | 1. One primitive: `Stream` (+ community-driven).
409 | 2. Separate packages for [subject-like](https://github.com/TylorS/most-subject) and [property-like](https://github.com/mostjs/hold) primitives.
410 | 3. Provides API to handle errors.
411 | 4. Provides API to handle ending.
412 |
413 | #### XStream
414 |
415 | 1. Two primitives: `Stream` and `MemoryStream` (like KefirJS).
416 | 2. Always multicast. A Stream is like an RxJS Subject.
417 | 3. Streams end on error.
418 |
419 | #### Common
420 |
421 | RxJS does not emit initial `scan` value as event (use `startWith` for that).
422 |
423 | ```js
424 | Rx.Observable.interval(100).map(x => 1)
425 | .scan(add, 0);
426 | .subscribe(console.log); // 1--2--3--...
427 |
428 | Most.periodic(100, 1)
429 | .scan(add, 0);
430 | .observe(console.log); // 0--1--2--3--...
431 | ```
432 |
433 | ### Found docs / API quirks
434 |
435 | #### MostJS
436 |
437 | `startWith` vs `sampleWith` vs `continueWith` + `recoverWith` vs `skipRepeatsWith`
438 | (val vs none vs func vs stream)
439 |
440 | `tap` is listed in "Transform" section.
441 |
442 | #### RxJS
443 |
444 | `startWith` is listed in "Combine" section.
445 |
446 | `mergeAll` is listed in "Combine" section.
447 |
448 | `distinct` is not listed in "Filtering" section.
449 |
450 | `takeUntil` is not listed in "Filtering" section.
451 |
452 | `just` / `return` should be deprecated in favor of `of`.
453 |
454 | `fromArray` should be deprecated in favor of `from`.
455 |
456 | ### Links
457 |
458 | [bacon-vs-kefir](https://github.com/rpominov/kefir/blob/master/bacon-vs-kefir-api.md) – BaconJS vs KefirJS API comparison
459 |
460 | [dataflows](https://github.com/ivan-kleshnin/dataflows) – web arch. dataflow comparison
461 |
462 | [stream-conversions](https://github.com/TylorS/stream-conversions) – tool for cross-library stream conversions
463 |
464 | ### Additional Read
465 |
466 | https://github.com/cujojs/most/issues/171
467 |
468 | https://twitter.com/rpominov/status/689566111734599683
469 |
470 | https://github.com/zenparsing/es-observable/issues/66
471 |
472 | # Reactive polyglot
473 |
474 | **`R.`** [(Ramda)](http://ramdajs.com/0.19.1/index.html) stands for standard functional toolkit.
475 |
476 | ### Comparison notes
477 |
478 | Operator counterparts aren't and can't be fully equivalent.
479 | "Kinda the same" – is the current definition.
480 |
481 | The following projects, were created with different goals and tradeoffs in mind, so every comparison
482 | and analogy is subjective and can be argued. The presence of some operator is not necessary good, as
483 | well as the abscence is not necessary bad.
484 |
485 | Note, that primitives differ for each library. In descriptions, we broadly refer to all the "observable
486 | primitives" as **streams***, though, technically speaking, some of them are rather stream-like entities.
487 |
488 | To find something, search for a term you know.
489 |
490 | ## API
491 |
492 | ### Create
493 |
494 | #### Create an empty stream
495 |
496 | * KefirJS: [`never`](http://kefirjs.github.io/kefir/#never)
497 | * MostJS: [`empty`](https://github.com/cujojs/most/blob/master/docs/api.md#mostempty)
498 | * RxJS: [`of`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/of.md)
499 | * XStream: [`empty`](https://github.com/staltz/xstream#of)
500 |
501 | #### Create a stream from a single value
502 |
503 | * KefirJS: [`constant`](http://kefirjs.github.io/kefir/#constant)
504 | * MostJS: [`of`](https://github.com/cujojs/most/blob/master/docs/api.md#mostjust), [`just`](https://github.com/cujojs/most/blob/master/docs/api.md#mostjust)
505 | * RxJS: [`of`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/of.md), [`just`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/return.md)
506 | * XStream: [`of`](https://github.com/staltz/xstream#of)
507 |
508 | #### Create a stream from an array
509 |
510 | * KefirJS: [`sequentially`](http://kefirjs.github.io/kefir/#sequentially)
511 | * MostJS: [`from`](https://github.com/cujojs/most/blob/master/docs/api.md#mostfrom)
512 | * RxJS: [`from`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/from.md), [`of`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/of.md)
513 | * XStream: [`from`](https://github.com/staltz/xstream#from), [`fromArray`](https://github.com/staltz/xstream#fromArray)
514 |
515 | #### Create a stream from a promise
516 |
517 | * KefirJS: [`fromPromise`](http://kefirjs.github.io/kefir/#from-promise)
518 | * MostJS: [`fromPromise`](https://github.com/cujojs/most/blob/master/docs/api.md#mostfrompromise)
519 | * RxJS: [`fromPromise`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/frompromise.md)
520 | * XStream: [`fromPromise`](https://github.com/staltz/xstream#fromPromise)
521 |
522 | #### Create a stream from an event
523 |
524 | * KefirJS: [`fromEvents`](http://kefirjs.github.io/kefir/#from-event)
525 | * MostJS: [`fromEvent`](https://github.com/cujojs/most/blob/master/docs/api.md#mostfromevent)
526 | * RxJS: [`fromEvent`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/fromevent.md)
527 | * XStream: [`fromEvent`](https://github.com/staltz/xstream/blob/master/EXTRA_DOCS.md#fromEvent)
528 |
529 | #### Create a stream from a callback
530 |
531 | * KefirJS: [`stream`](http://kefirjs.github.io/kefir/#stream), [`fromCallback`](http://kefirjs.github.io/kefir/#from-callback), [`fromNodeCallback`](http://kefirjs.github.io/kefir/#from-node-callback), [`fromPoll`](http://kefirjs.github.io/kefir/#from-poll)
532 | * MostJS: `new Stream`
533 | * RxJS: `new Observable`, `bindCallback`, `bindNodeCallback`
534 | * XStream: `? (make a promise first)`
535 |
536 | #### Prepend a stream with a value
537 |
538 | * KefirJS: [`merge`](http://kefirjs.github.io/kefir/#merge) `+` [`constant`](http://kefirjs.github.io/kefir/#constant)
539 | * MostJS: `startWith`
540 | * RxJS: `startWith`
541 | * XStream: `startWith`
542 |
543 | ### Transform (data events)
544 |
545 | #### Map value one-to-one
546 |
547 | * KefirJS: [`map`](http://kefirjs.github.io/kefir/#map)
548 | * MostJS: `map`, `constant`
549 | * RxJS: `map`, `mapTo`
550 | * XStream: `map`
551 |
552 | #### Filter value by a predicate
553 |
554 | * KefirJS: [`filter`](http://kefirjs.github.io/kefir/#filter)
555 | * MostJS: `filter`
556 | * RxJS: `filter`
557 | * XStream: `filter`
558 |
559 | #### Skip N initial values
560 |
561 | * KefirJS: [`skip`](http://kefirjs.github.io/kefir/#skip)
562 | * MostJS: `skip`
563 | * RxJS: `skip`
564 | * XStream: `drop`
565 |
566 | #### Take N initial values
567 |
568 | * KefirJS: [`take`](http://kefirjs.github.io/kefir/#take)
569 | * MostJS: `take`
570 | * RxJS: `take`
571 | * XStream: `take`
572 |
573 | #### Make a value from an accumulator and a next value
574 |
575 | * KefirJS: [`scan`](http://kefirjs.github.io/kefir/#scan)
576 | * MostJS: `scan`
577 | * RxJS: `scan`
578 | * XStream: `fold`
579 |
580 | ### Combine
581 |
582 | #### Merge multiple streams together
583 |
584 | * KefirJS: [`merge`](http://kefirjs.github.io/kefir/#merge)
585 | * MostJS: `merge`
586 | * RxJS: `merge`
587 | * XStream: `merge`
588 |
589 | Pay attention that Kefir's `merge` accepts arrays while others are variadic.
590 |
591 | #### Combine multiple streams together
592 |
593 | * KefirJS: [`combine`](http://kefirjs.github.io/kefir/#combine)
594 | * MostJS: `combine`
595 | * RxJS: `combineLatest`
596 | * XStream: `combine`
597 |
598 | #### Sample a stream by another stream
599 |
600 | * KefirJS: [`combine`](http://kefirjs.github.io/kefir/#combine), [`sampledBy`](http://kefirjs.github.io/kefir/#obs-sampled-by)
601 | * MostJS: `sample`, `sampleWith`
602 | * RxJS: `sample`, `withLatestFrom`
603 | * XStream: `sampleCombine`
604 |
605 | #### Chain streams sequentially
606 |
607 | * KefirJS: [`flatMapConcat`](http://kefirjs.github.io/kefir/#flat-map-concat)
608 | * MostJS: `concatMap`
609 | * RxJS: `concatMap`
610 | * XStream: `map + flattenSequentially`
611 |
612 | ---
613 |
614 | ### Create
615 |
616 | Create stream from non-stream values.
617 |
618 |
619 |
620 | | KefirJS |
621 | MostJS |
622 | RxJS |
623 | XStream |
624 |
625 |
626 | interval |
627 | periodic |
628 | interval + map |
629 | periodic |
630 |
631 |
632 | repeat |
633 | of + R.range |
634 | repeat |
635 | of + R.range |
636 |
637 |
638 | ? |
639 | iterate |
640 | generate |
641 | ? |
642 |
643 |
644 | ? |
645 | generate |
646 | generate |
647 | ? |
648 |
649 |
650 |
651 | ### Mapper
652 |
653 | Modify events one to one.
654 |
655 |
656 |
657 | | KefirJS |
658 | MostJS |
659 | RxJS |
660 | XStream |
661 |
662 |
663 | delay |
664 | delay |
665 | delay |
666 | combine(delay(500)) |
667 |
668 |
669 | – (map) |
670 | timestamp |
671 | timestamp |
672 | – (map) |
673 |
674 |
675 |
676 | ### Transforms
677 |
678 | Modify events * to *.
679 |
680 |
681 |
682 | | MostJS |
683 | RxJS |
684 | XStream |
685 |
686 |
687 | chain / flatMap |
688 | flatMap |
689 | map + flattenConcurrently |
690 |
691 |
692 | map + switch |
693 | switchMap / flatMapLatest |
694 | map + flatten |
695 |
696 |
697 | join |
698 | mergeAll |
699 | flatten |
700 |
701 |
702 | loop |
703 | scan + map |
704 | fold + map |
705 |
706 |
707 | – (custom) |
708 | bufferWithCount |
709 | ? |
710 |
711 |
712 |
713 | ### Filters
714 |
715 | Skip events by predicate or signal.
716 |
717 |
718 |
719 | | MostJS |
720 | RxJS |
721 | XStream |
722 |
723 |
724 | skipRepeats |
725 | distinctUntilChanged |
726 | dropRepeats |
727 |
728 |
729 | skipRepeatsWith |
730 | – (scan) |
731 | dropRepeats |
732 |
733 |
734 | slice |
735 | skip + take |
736 | drop + take |
737 |
738 |
739 | skipWhile |
740 | skipWhile |
741 | fold + filter + map |
742 |
743 |
744 | takeWhile |
745 | takeWhile |
746 | filter + endWhen |
747 |
748 |
749 | since / skipUntil |
750 | skipUntil |
751 | fold + filter + map |
752 |
753 |
754 | until / takeUntil |
755 | takeUntil |
756 | filter + endWhen |
757 |
758 |
759 | during |
760 | window + take(1) |
761 | ? |
762 |
763 |
764 |
765 | ### Combinators
766 |
767 | Combine multiple streams into single.
768 |
769 |
770 |
771 | | MostJS |
772 | RxJS |
773 | XStream |
774 |
775 |
776 | zip |
777 | zip |
778 | ? |
779 |
780 |
781 | concat |
782 | concat |
783 | concat |
784 |
785 |
786 | ap |
787 | combineLatest |
788 | ? |
789 |
790 |
791 |
792 | ### Side effects
793 |
794 | Produce side effect for every event.
795 |
796 |
797 |
798 | | MostJS |
799 | RxJS |
800 | XStream |
801 |
802 |
803 | tap |
804 | do / tap |
805 | debug |
806 |
807 |
808 |
809 | ### Ending
810 |
811 | Operators which target **end** event somehow.
812 |
813 |
814 |
815 | | MostJS |
816 | RxJS |
817 | XStream |
818 |
819 |
820 | empty |
821 | empty |
822 | empty |
823 |
824 |
825 | never |
826 | never |
827 | never |
828 |
829 |
830 | continueWith |
831 | ? |
832 | concat |
833 |
834 |
835 |
836 | ### Concurrency
837 |
838 |
839 |
840 | | MostJS |
841 | RxJS |
842 |
843 |
844 | – (custom) |
845 | amb / race |
846 |
847 |
848 |
849 | ### History
850 |
851 |
852 |
853 | | MostJS |
854 | RxJS |
855 |
856 |
857 | – (custom) |
858 |
859 |
860 |
861 | ### Design diffs
862 |
863 | #### RxJS
864 |
865 | 1. Three primitives: `Observer`, `Observable`, `Subject`.
866 | 2. Observables end on error.
867 | 3. Provides API to handle errors.
868 | 3. Does not provide API to handle ending.
869 |
870 | #### KefirJS
871 |
872 | 1. Two primitives: `Stream` and `Property` (like XStream).
873 | 2. Observables does not end on error (by default).
874 | 3. Provides API to handle errors.
875 | 4. Provides API to handle ending.
876 |
877 | #### MostJS
878 |
879 | 1. One primitive: `Stream` (+ community-driven).
880 | 2. Separate packages for [subject-like](https://github.com/TylorS/most-subject) and [property-like](https://github.com/mostjs/hold) primitives.
881 | 3. Provides API to handle errors.
882 | 4. Provides API to handle ending.
883 |
884 | #### XStream
885 |
886 | 1. Two primitives: `Stream` and `MemoryStream` (like KefirJS).
887 | 2. Always multicast. A Stream is like an RxJS Subject.
888 | 3. Streams end on error.
889 |
890 | #### Common
891 |
892 | RxJS does not emit initial `scan` value as event (use `startWith` for that).
893 |
894 | ```js
895 | Rx.Observable.interval(100).map(x => 1)
896 | .scan(add, 0);
897 | .subscribe(console.log); // 1--2--3--...
898 |
899 | Most.periodic(100, 1)
900 | .scan(add, 0);
901 | .observe(console.log); // 0--1--2--3--...
902 | ```
903 |
904 | ### Found docs / API quirks
905 |
906 | #### MostJS
907 |
908 | `startWith` vs `sampleWith` vs `continueWith` + `recoverWith` vs `skipRepeatsWith`
909 | (val vs none vs func vs stream)
910 |
911 | `tap` is listed in "Transform" section.
912 |
913 | #### RxJS
914 |
915 | `startWith` is listed in "Combine" section.
916 |
917 | `mergeAll` is listed in "Combine" section.
918 |
919 | `distinct` is not listed in "Filtering" section.
920 |
921 | `takeUntil` is not listed in "Filtering" section.
922 |
923 | `just` / `return` should be deprecated in favor of `of`.
924 |
925 | `fromArray` should be deprecated in favor of `from`.
926 |
927 | ### Links
928 |
929 | [bacon-vs-kefir](https://github.com/rpominov/kefir/blob/master/bacon-vs-kefir-api.md) – BaconJS vs KefirJS API comparison
930 |
931 | [dataflows](https://github.com/ivan-kleshnin/dataflows) – web arch. dataflow comparison
932 |
933 | [stream-conversions](https://github.com/TylorS/stream-conversions) – tool for cross-library stream conversions
934 |
935 | ### Additional Read
936 |
937 | https://github.com/cujojs/most/issues/171
938 |
939 | https://twitter.com/rpominov/status/689566111734599683
940 |
941 | https://github.com/zenparsing/es-observable/issues/66
942 |
943 |
944 |
--------------------------------------------------------------------------------