UNPKG

17.7 kBMarkdownView Raw
1<!-- This EXTRA_DOCS.md file is automatically generated from source code and files in the /markdown directory. Please DO NOT send pull requests to directly modify this file. Instead, edit the JSDoc comments in source code or the md files in /markdown or the md.ejs files in /tools. -->
2
3## Extras
4
5- [`concat`](#concat) (factory)
6- [`debounce`](#debounce) (operator)
7- [`delay`](#delay) (operator)
8- [`dropRepeats`](#dropRepeats) (operator)
9- [`dropUntil`](#dropUntil) (operator)
10- [`flattenConcurrently`](#flattenConcurrently) (operator)
11- [`flattenSequentially`](#flattenSequentially) (operator)
12- [`fromDiagram`](#fromDiagram) (factory)
13- [`fromEvent`](#fromEvent) (operator)
14- [`pairwise`](#pairwise) (operator)
15- [`sampleCombine`](#sampleCombine) (operator)
16- [`split`](#split) (operator)
17- [`throttle`](#throttle) (operator)
18- [`tween`](#tween) (factory)
19
20# How to use extras
21
22The following are standalone stream operators and stream factories that may be separately imported and utilized in your project.
23To use an extra operator (e.g. `delay`), import it as such:
24
25```js
26import xs from 'xstream'
27import delay from 'xstream/extra/delay'
28
29const inputStream = xs.of(1, 2, 3, 4)
30const outputStream = inputStream.compose(delay(500))
31```
32
33To import and use an extra factory (e.g. `fromEvent`), import it as such:
34
35```js
36import fromEvent from 'xstream/extra/fromEvent'
37
38const clickStream = fromEvent(document, 'click')
39```
40
41- - -
42
43### <a id="concat"></a> `concat(stream1, stream2)`
44
45Puts one stream after the other. *concat* is a factory that takes multiple
46streams as arguments, and starts the `n+1`-th stream only when the `n`-th
47stream has completed. It concatenates those streams together.
48
49Marble diagram:
50
51```text
52--1--2---3---4-|
53...............--a-b-c--d-|
54 concat
55--1--2---3---4---a-b-c--d-|
56```
57
58Example:
59
60```js
61import concat from 'xstream/extra/concat'
62
63const streamA = xs.of('a', 'b', 'c')
64const streamB = xs.of(10, 20, 30)
65const streamC = xs.of('X', 'Y', 'Z')
66
67const outputStream = concat(streamA, streamB, streamC)
68
69outputStream.addListener({
70 next: (x) => console.log(x),
71 error: (err) => console.error(err),
72 complete: () => console.log('concat completed'),
73})
74```
75
76#### Arguments:
77
78- `stream1: Stream` A stream to concatenate together with other streams.
79- `stream2: Stream` A stream to concatenate together with other streams. Two or more streams may be given as arguments.
80
81#### Returns: Stream
82
83- - -
84
85### <a id="debounce"></a> `debounce(period)`
86
87Delays events until a certain amount of silence has passed. If that timespan
88of silence is not met the event is dropped.
89
90Marble diagram:
91
92```text
93--1----2--3--4----5|
94 debounce(60)
95-----1----------4--|
96```
97
98Example:
99
100```js
101import fromDiagram from 'xstream/extra/fromDiagram'
102import debounce from 'xstream/extra/debounce'
103
104const stream = fromDiagram('--1----2--3--4----5|')
105 .compose(debounce(60))
106
107stream.addListener({
108 next: i => console.log(i),
109 error: err => console.error(err),
110 complete: () => console.log('completed')
111})
112```
113
114```text
115> 1
116> 4
117> completed
118```
119
120#### Arguments:
121
122- `period: number` The amount of silence required in milliseconds.
123
124#### Returns: Stream
125
126- - -
127
128### <a id="delay"></a> `delay(period)`
129
130Delays periodic events by a given time period.
131
132Marble diagram:
133
134```text
1351----2--3--4----5|
136 delay(60)
137---1----2--3--4----5|
138```
139
140Example:
141
142```js
143import fromDiagram from 'xstream/extra/fromDiagram'
144import delay from 'xstream/extra/delay'
145
146const stream = fromDiagram('1----2--3--4----5|')
147 .compose(delay(60))
148
149stream.addListener({
150 next: i => console.log(i),
151 error: err => console.error(err),
152 complete: () => console.log('completed')
153})
154```
155
156```text
157> 1 (after 60 ms)
158> 2 (after 160 ms)
159> 3 (after 220 ms)
160> 4 (after 280 ms)
161> 5 (after 380 ms)
162> completed
163```
164
165#### Arguments:
166
167- `period: number` The amount of silence required in milliseconds.
168
169#### Returns: Stream
170
171- - -
172
173### <a id="dropRepeats"></a> `dropRepeats(isEqual)`
174
175Drops consecutive duplicate values in a stream.
176
177Marble diagram:
178
179```text
180--1--2--1--1--1--2--3--4--3--3|
181 dropRepeats
182--1--2--1--------2--3--4--3---|
183```
184
185Example:
186
187```js
188import dropRepeats from 'xstream/extra/dropRepeats'
189
190const stream = xs.of(1, 2, 1, 1, 1, 2, 3, 4, 3, 3)
191 .compose(dropRepeats())
192
193stream.addListener({
194 next: i => console.log(i),
195 error: err => console.error(err),
196 complete: () => console.log('completed')
197})
198```
199
200```text
201> 1
202> 2
203> 1
204> 2
205> 3
206> 4
207> 3
208> completed
209```
210
211Example with a custom isEqual function:
212
213```js
214import dropRepeats from 'xstream/extra/dropRepeats'
215
216const stream = xs.of('a', 'b', 'a', 'A', 'B', 'b')
217 .compose(dropRepeats((x, y) => x.toLowerCase() === y.toLowerCase()))
218
219stream.addListener({
220 next: i => console.log(i),
221 error: err => console.error(err),
222 complete: () => console.log('completed')
223})
224```
225
226```text
227> a
228> b
229> a
230> B
231> completed
232```
233
234#### Arguments:
235
236- `isEqual: Function` An optional function of type `(x: T, y: T) => boolean` that takes an event from the input stream and
237checks if it is equal to previous event, by returning a boolean.
238
239#### Returns: Stream
240
241- - -
242
243### <a id="dropUntil"></a> `dropUntil(other)`
244
245Starts emitting the input stream when another stream emits a next event. The
246output stream will complete if/when the other stream completes.
247
248Marble diagram:
249
250```text
251---1---2-----3--4----5----6---
252 dropUntil( --------a--b--| )
253---------------------5----6|
254```
255
256Example:
257
258```js
259import dropUntil from 'xstream/extra/dropUntil'
260
261const other = xs.periodic(220).take(1)
262
263const stream = xs.periodic(50)
264 .take(6)
265 .compose(dropUntil(other))
266
267stream.addListener({
268 next: i => console.log(i),
269 error: err => console.error(err),
270 complete: () => console.log('completed')
271})
272```
273
274```text
275> 4
276> 5
277> completed
278```
279
280#### Arguments:
281
282#### Arguments:
283
284- `other: Stream` Some other stream that is used to know when should the output stream of this operator start emitting.
285
286#### Returns: Stream
287
288- - -
289
290### <a id="flattenConcurrently"></a> `flattenConcurrently()`
291
292Flattens a "stream of streams", handling multiple concurrent nested streams
293simultaneously.
294
295If the input stream is a stream that emits streams, then this operator will
296return an output stream which is a flat stream: emits regular events. The
297flattening happens concurrently. It works like this: when the input stream
298emits a nested stream, *flattenConcurrently* will start imitating that
299nested one. When the next nested stream is emitted on the input stream,
300*flattenConcurrently* will also imitate that new one, but will continue to
301imitate the previous nested streams as well.
302
303Marble diagram:
304
305```text
306--+--------+---------------
307 \ \
308 \ ----1----2---3--
309 --a--b----c----d--------
310 flattenConcurrently
311-----a--b----c-1--d-2---3--
312```
313
314#### Returns: Stream
315
316- - -
317
318### <a id="flattenSequentially"></a> `flattenSequentially()`
319
320Flattens a "stream of streams", handling only one nested stream at a time,
321with no concurrency, but does not drop nested streams like `flatten` does.
322
323If the input stream is a stream that emits streams, then this operator will
324return an output stream which is a flat stream: emits regular events. The
325flattening happens sequentially and without concurrency. It works like this:
326when the input stream emits a nested stream, *flattenSequentially* will start
327imitating that nested one. When the next nested stream is emitted on the
328input stream, *flattenSequentially* will keep that in a buffer, and only
329start imitating it once the previous nested stream completes.
330
331In essence, `flattenSequentially` concatenates all nested streams.
332
333Marble diagram:
334
335```text
336--+--------+-------------------------
337 \ \
338 \ ----1----2---3--|
339 --a--b----c----d--|
340 flattenSequentially
341-----a--b----c----d------1----2---3--
342```
343
344#### Returns: Stream
345
346- - -
347
348### <a id="fromDiagram"></a> `fromDiagram(diagram, options)`
349
350Creates a real stream out of an ASCII drawing of a stream. Each string
351character represents an amount of time passed (by default, 20 milliseconds).
352`-` characters represent nothing special, `|` is a symbol to mark the
353completion of the stream, `#` is an error on the stream, and any other
354character is a "next" event.
355
356Example:
357
358```js
359import fromDiagram from 'xstream/extra/fromDiagram'
360
361const stream = fromDiagram('--a--b---c-d--|')
362
363stream.addListener({
364 next: (x) => console.log(x),
365 error: (err) => console.error(err),
366 complete: () => console.log('concat completed'),
367})
368```
369
370The character `a` represent emission of the event `'a'`, a string. If you
371want to emit something else than a string, you need to provide those values
372in the options argument.
373
374Example:
375
376```js
377import fromDiagram from 'xstream/extra/fromDiagram'
378
379const stream = fromDiagram('--a--b---c-d--|', {
380 values: {a: 10, b: 20, c: 30, d: 40}
381})
382
383stream.addListener({
384 next: (x) => console.log(x),
385 error: (err) => console.error(err),
386 complete: () => console.log('concat completed'),
387})
388```
389
390That way, the stream will emit the numbers 10, 20, 30, 40. The `options`
391argument may also take `timeUnit`, a number to configure how many
392milliseconds does each represents, and `errorValue`, a value to send out as
393the error which `#` represents.
394
395#### Arguments:
396
397- `diagram: string` A string representing a timeline of values, error, or complete notifications that should happen on the output stream.
398- `options` An options object that allows you to configure some additional details of the creation of the stream.
399
400#### Returns: Stream
401
402- - -
403
404### <a id="fromEvent"></a> `fromEvent(element, eventName, useCapture)`
405
406Creates a stream based on either:
407- DOM events with the name `eventName` from a provided target node
408- Events with the name `eventName` from a provided NodeJS EventEmitter
409
410When creating a stream from EventEmitters, if the source event has more than
411one argument all the arguments will be aggregated into an array in the
412result stream.
413
414Marble diagram:
415
416```text
417 fromEvent(element, eventName)
418---ev--ev----ev---------------
419```
420
421Examples:
422
423```js
424import fromEvent from 'xstream/extra/fromEvent'
425
426const stream = fromEvent(document.querySelector('.button'), 'click')
427 .mapTo('Button clicked!')
428
429stream.addListener({
430 next: i => console.log(i),
431 error: err => console.error(err),
432 complete: () => console.log('completed')
433})
434```
435
436```text
437> 'Button clicked!'
438> 'Button clicked!'
439> 'Button clicked!'
440```
441
442```js
443import fromEvent from 'xstream/extra/fromEvent'
444import {EventEmitter} from 'events'
445
446const MyEmitter = new EventEmitter()
447const stream = fromEvent(MyEmitter, 'foo')
448
449stream.addListener({
450 next: i => console.log(i),
451 error: err => console.error(err),
452 complete: () => console.log('completed')
453})
454
455MyEmitter.emit('foo', 'bar')
456```
457
458```text
459> 'bar'
460```
461
462```js
463import fromEvent from 'xstream/extra/fromEvent'
464import {EventEmitter} from 'events'
465
466const MyEmitter = new EventEmitter()
467const stream = fromEvent(MyEmitter, 'foo')
468
469stream.addListener({
470 next: i => console.log(i),
471 error: err => console.error(err),
472 complete: () => console.log('completed')
473})
474
475MyEmitter.emit('foo', 'bar', 'baz', 'buzz')
476```
477
478```text
479> ['bar', 'baz', 'buzz']
480```
481
482#### Arguments:
483
484- `element: EventTarget|EventEmitter` The element upon which to listen.
485- `eventName: string` The name of the event for which to listen.
486- `useCapture: boolean` An optional boolean that indicates that events of this type will be dispatched to the registered listener before being
487dispatched to any EventTarget beneath it in the DOM tree. Defaults to false.
488
489#### Returns: Stream
490
491- - -
492
493### <a id="pairwise"></a> `pairwise()`
494
495Group consecutive pairs of events as arrays. Each array has two items.
496
497Marble diagram:
498
499```text
500---1---2-----3-----4-----5--------|
501 pairwise
502-------[1,2]-[2,3]-[3,4]-[4,5]----|
503```
504
505Example:
506
507```js
508import pairwise from 'xstream/extra/pairwise'
509
510const stream = xs.of(1, 2, 3, 4, 5, 6).compose(pairwise)
511
512stream.addListener({
513 next: i => console.log(i),
514 error: err => console.error(err),
515 complete: () => console.log('completed')
516})
517```
518
519```text
520> [1,2]
521> [2,3]
522> [3,4]
523> [4,5]
524> [5,6]
525> completed
526```
527
528#### Returns: Stream
529
530- - -
531
532### <a id="sampleCombine"></a> `sampleCombine(streams)`
533
534Combines a source stream with multiple other streams. The result stream
535will emit the latest events from all input streams, but only when the
536source stream emits.
537
538If the source, or any input stream, throws an error, the result stream
539will propagate the error. If any input streams end, their final emitted
540value will remain in the array of any subsequent events from the result
541stream.
542
543The result stream will only complete upon completion of the source stream.
544
545Marble diagram:
546
547```text
548--1----2-----3--------4--- (source)
549----a-----b-----c--d------ (other)
550 sampleCombine
551-------2a----3b-------4d--
552```
553
554Examples:
555
556```js
557import sampleCombine from 'xstream/extra/sampleCombine'
558import xs from 'xstream'
559
560const sampler = xs.periodic(1000).take(3)
561const other = xs.periodic(100)
562
563const stream = sampler.compose(sampleCombine(other))
564
565stream.addListener({
566 next: i => console.log(i),
567 error: err => console.error(err),
568 complete: () => console.log('completed')
569})
570```
571
572```text
573> [0, 8]
574> [1, 18]
575> [2, 28]
576```
577
578```js
579import sampleCombine from 'xstream/extra/sampleCombine'
580import xs from 'xstream'
581
582const sampler = xs.periodic(1000).take(3)
583const other = xs.periodic(100).take(2)
584
585const stream = sampler.compose(sampleCombine(other))
586
587stream.addListener({
588 next: i => console.log(i),
589 error: err => console.error(err),
590 complete: () => console.log('completed')
591})
592```
593
594```text
595> [0, 1]
596> [1, 1]
597> [2, 1]
598```
599
600#### Arguments:
601
602- `streams: Stream` One or more streams to combine with the sampler stream.
603
604#### Returns: Stream
605
606- - -
607
608### <a id="split"></a> `split(separator)`
609
610Splits a stream using a separator stream. Returns a stream that emits
611streams.
612
613Marble diagram:
614
615```text
616--1--2--3--4--5--6--7--8--9|
617 split( --a----b--- )
618---------------------------|
619 : : :
620 1--2--3-|: :
621 4--5|:
622 -6--7--8--9|
623```
624
625Example:
626
627```js
628import split from 'xstream/extra/split'
629import concat from 'xstream/extra/concat'
630
631const source = xs.periodic(50).take(10)
632const separator = concat(xs.periodic(167).take(2), xs.never())
633const result = source.compose(split(separator))
634
635result.addListener({
636 next: stream => {
637 stream.addListener({
638 next: i => console.log(i),
639 error: err => console.error(err),
640 complete: () => console.log('inner completed')
641 })
642 },
643 error: err => console.error(err),
644 complete: () => console.log('outer completed')
645})
646```
647
648```text
649> 0
650> 1
651> 2
652> inner completed
653> 3
654> 4
655> 5
656> inner completed
657> 6
658> 7
659> 8
660> 9
661> inner completed
662> outer completed
663```
664
665#### Arguments:
666
667- `separator: Stream` Some other stream that is used to know when to split the output stream.
668
669#### Returns: Stream
670
671- - -
672
673### <a id="throttle"></a> `throttle(period)`
674
675Emits event and drops subsequent events until a certain amount of silence has passed.
676
677Marble diagram:
678
679```text
680--1-2-----3--4----5|
681 throttle(60)
682--1-------3-------5-|
683```
684
685Example:
686
687```js
688import fromDiagram from 'xstream/extra/fromDiagram'
689import throttle from 'xstream/extra/throttle'
690
691const stream = fromDiagram('--1-2-----3--4----5|')
692 .compose(throttle(60))
693
694stream.addListener({
695 next: i => console.log(i),
696 error: err => console.error(err),
697 complete: () => console.log('completed')
698})
699```
700
701```text
702> 1
703> 3
704> 5
705> completed
706```
707
708#### Arguments:
709
710- `period: number` The amount of silence required in milliseconds.
711
712#### Returns: Stream
713
714- - -
715
716### <a id="tween"></a> `tween(config)`
717
718Creates a stream of numbers emitted in a quick burst, following a numeric
719function like sine or elastic or quadratic. tween() is meant for creating
720streams for animations.
721
722Example:
723
724```js
725import tween from 'xstream/extra/tween'
726
727const stream = tween({
728 from: 20,
729 to: 100,
730 ease: tween.exponential.easeIn,
731 duration: 1000, // milliseconds
732})
733
734stream.addListener({
735 next: (x) => console.log(x),
736 error: (err) => console.error(err),
737 complete: () => console.log('concat completed'),
738})
739```
740
741The stream would behave like the plot below:
742
743```text
744100 #
745|
746|
747|
748|
74980 #
750|
751|
752|
753| #
75460
755|
756| #
757|
758| #
75940
760| #
761| #
762| ##
763| ###
76420########
765+---------------------> time
766```
767
768Provide a configuration object with **from**, **to**, **duration**, **ease**,
769**interval** (optional), and this factory function will return a stream of
770numbers following that pattern. The first number emitted will be `from`, and
771the last number will be `to`. The numbers in between follow the easing
772function you specify in `ease`, and the stream emission will last in total
773`duration` milliseconds.
774
775The easing functions are attached to `tween` too, such as
776`tween.linear.ease`, `tween.power2.easeIn`, `tween.exponential.easeOut`, etc.
777Here is a list of all the available easing options:
778
779- `tween.linear` with ease
780- `tween.power2` with easeIn, easeOut, easeInOut
781- `tween.power3` with easeIn, easeOut, easeInOut
782- `tween.power4` with easeIn, easeOut, easeInOut
783- `tween.exponential` with easeIn, easeOut, easeInOut
784- `tween.back` with easeIn, easeOut, easeInOut
785- `tween.bounce` with easeIn, easeOut, easeInOut
786- `tween.circular` with easeIn, easeOut, easeInOut
787- `tween.elastic` with easeIn, easeOut, easeInOut
788- `tween.sine` with easeIn, easeOut, easeInOut
789
790#### Arguments:
791
792- `config: TweenConfig` An object with properties `from: number`, `to: number`, `duration: number`, `ease: function` (optional, defaults to
793linear), `interval: number` (optional, defaults to 15).
794
795#### Returns: Stream
796
797- - -
798