Sharing cold and hot observables - reactive-programming

I'm confused by the behavior of a shared stream that is created using Rx.Observable.just.
For example:
var log = function(x) { console.log(x); };
var cold = Rx.Observable
.just({ foo: 'cold' });
cold.subscribe(log); // <-- Logs three times
cold.subscribe(log);
cold.subscribe(log);
var coldShare = Rx.Observable
.just({ foo: 'cold share' })
.share();
coldShare.subscribe(log); // <-- Only logs once
coldShare.subscribe(log);
coldShare.subscribe(log);
Both streams only emit one event, but the un-shared one can be subscribed to three times. Why is this?
I need to "fork" a stream but share its value (and then combine the forked streams).
How can I share the value of a stream but also subscribe to it multiple times?
I realize that this is probably related to the concept of "cold" and "hot" observables. However:
Is the stream created by Rx.Observable.just() cold or hot?
How is one supposed to determine the answer to the previous question?

Is the stream created by Rx.Observable.just() cold or hot?
Cold.
How is one supposed to determine the answer to the previous question?
I guess the documentation is the only guide.
How can I share the value of a stream but also subscribe to it multiple times?
You are looking for the idea of a connectable observable. By example:
var log = function(x) { console.log(x); };
var coldShare = Rx.Observable
.just({ foo: 'cold share' })
.publish();
coldShare.subscribe(log); // Does nothing
coldShare.subscribe(log); // Does nothing
coldShare.subscribe(log); // Does nothing
coldShare.connect(); // Emits one value to its three subscribers (logs three times)
var log = function(x) {
document.write(JSON.stringify(x));
document.write("<br>");
};
var coldShare = Rx.Observable
.just({ foo: 'cold share' })
.publish();
coldShare.subscribe(log); // <-- Only logs once
coldShare.subscribe(log);
coldShare.subscribe(log);
coldShare.connect();
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.min.js"></script>
The example above logs three times. Using publish and connect, you essentially "pause" the observable until the call to connect.
See also:
How do I share an observable with publish and connect?
Are there 'hot' and 'cold' operators?

I don-t understand your first question, but about the last one, as I have been having problem getting that one too:
Rxjs implementation of Observables/Observers is based on the observer pattern, which is similar to the good old callback mechanism.
To exemplify, here is the basic form of creating an observable (taken from the doc at https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/create.md)
var source = Rx.Observable.create(function (observer) {
observer.onNext(42);
observer.onCompleted();
// Note that this is optional, you do not have to return this if you require no cleanup
return function () {
console.log('disposed');
};
});
Rx.Observable.create takes as argument a function (say factory_fn to be original) which takes an observer. Your values are generated by a computation of your choice in the body of factory_fn, and because you have the observer in parameter you can process/push the generated values when you see fit. BUT factory_fn is not executed, it is just registered (like a callback would). It will be called everytime there is a subscribe(observer) on the related observable (i.e. the one returned by Rx.Observable.create(factory_fn).
Once subscription is done (creation callback called), values flow to your observer according to the logic in the factory function and it remains that way till your observable completes or the observer unsubscribes (supposing you did implement an action to cancel value flow as the return value of factory_fn).
What that basically means is by default, Rx.Observables are cold.
My conclusion after using quite a bit of the library, is that unless it is duely documented, the only way to know FOR SURE the temperature of an observable is to eye the source code. Or add a side effect somewhere, subscribe twice and see if the side effect happens twice or only once (which is what you did). That, or ask on stackoverflow.
For instance, Rx.fromEvent produce hot observables, as you can see from the last line in the code (return new EventObservable(element, eventName, selector).publish().refCount();). (code here : https://github.com/Reactive-Extensions/RxJS/blob/master/src/core/linq/observable/fromevent.js). The publish operator is among those operators which turns a cold observable into a hot one. How that works is out of scope so I won-t detail it here.
But Rx.DOM.fromWebSocket does not produce hot observables (https://github.com/Reactive-Extensions/RxJS-DOM/blob/master/src/dom/websocket.js). Cf. How to buffer stream using fromWebSocket Subject
Confusion often comes I think from the fact that we conflate the actual source (say stream of button clicks) and its representation (Rx.Observable). It is unfortunate when that happens but what we imagine as hot sources can end up being represented by a cold Rx.Observable.
So, yes, Rx.Observable.just creates cold observables.

Related

rxdart: Get buffered elements on stream subscription cancel

I'm using a rxdart ZipStream within my app to combine two streams of incoming bluetooth data. Those streams are used along with "bufferCount" to collect 500 elements each before emitting. Everything works fine so far, but if the stream subscription gets cancelled at some point, there might be a number of elements in those buffers that are omitted after that. I could wait for a "buffer cycle" to complete before cancelling the stream subscription, but as this might take some time depending on the configured sample rate, I wonder if there is a solution to get those buffers as they are even if the number of elements might be less than 500.
Here is some simplified code for explanation:
subscription = ZipStream.zip2(
streamA.bufferCount(500),
streamB.bufferCount(500),
(streamABuffer, streamBBuffer) {
return ...;
},
).listen((data) {
...
});
Thanks in advance!
So for anyone wondering: As bufferCount is implemented with BufferCountStreamTransformer which extends BackpressureStreamTransformer, there is a dispatchOnClose property that defaults to true. That means if the underlying stream whose emitted elements are buffered is closed, then the remaining elements in that buffer are emitted finally. This also applies to the example above. My fault was to close the stream and to cancel the stream subscription instantly. With awaiting the stream's closing and cancelling the stream subscription afterwards, everything works as expected.

Avoiding repetitive calls when creating reactfire hooks

When initializing a component using reactfire, each time I add a reactfire hook (e.g. useFirestoreDocData), it triggers a re-render and therefore repeats all previous initialization. For example:
const MyComponent = props => {
console.log(1);
const firestore = useFirestore();
console.log(2);
const ref = firestore.doc('count/counter');
console.log(3);
const { value } = useFirestoreDocDataOnce(ref);
console.log(4);
...
return <span>{value}</span>;
};
will output:
1
1
2
3
1
2
3
4
This seems wasteful, is there a way to avoid this?
This is particularly problematic when I need the result of one reactfire hook to create another (e.g. retrieve data from one document to determine which other document to read) and it duplicates the server calls.
See React's documentation of Suspense.
Particulary that part: Approach 3: Render-as-You-Fetch (using Suspense)
Reactfire uses this mechanics. It is not supposed to fetch more than one time for each call even if the line is executed more than once. The mechanics behind "understand" that the fetch is already done and will start the next one.
In your case, react try to render your component, see it needs to fetch, stop rendering and show suspense's fallback while fetching. When fetch is done it retry to render your component and as the fetch is completed it will render completely.
You can confirm in your network tab that each calls is done only once.
I hope I'm clear, please don't hesitate to ask for more details if i'm not.

Reactive programming: Emit a specified element when a stream is idle for some time

I have an observable object and I want to emit a default element after some time has passed (a timeout) while keeping the stream still open to emit new values in the future. How can I do this?
I attempted to do this by doing a merge of the original stream with another stream that debounces the original one while mapping the debounced value to the default that I want.
Pseudocode:
defaultDebounced = originalStream.debounce(time).map({x -> myDefaultValue})
myStream = rx.merge(originalStream, defaultDebounced)
though I don't know if I would run into some border cases like the following in which the original stream emits an item just as the timeout triggers and by chance, the default value gets emitted afterwards.
original: ----A----B----------------------C------------
debounced: -----------------------<timeout>X------------
merged: --------------------------------CX-----------
Also, there's the downside that the first observable has to emit at least one item in order for debounce to emit the default value.
Note: I would like to know the proper rx way to do it, regardless of the implementation, but just in case I'm working on RxSwift.
What I finally did was:
originalStream.flatMapLatest({x ->
return Observable.timer(30, scheduler: MainScheduler.instance)
.map{_ -> defaultValue}
.startWith(x)
})

Amount of flatMap executions depends on observer pull, while single is needed

I have a push notification mechanism (PublishSubject) which triggers http request logic (flatMap). Basic scenario is that whenever a push arrives, single http call is made and results propagated to multiple observers.
I've written a simple demo for the case but flatMap executes for each registered observer, while I would like it to be triggered just once on each push.
PublishSubject<Integer> subject = PublishSubject.create();
Observable<String> obs = subject.asObservable().flatMap(integer -> {
// this code runs for each observer, which is twice in this case
return Observable.just(String.valueOf(integer));
});
Observer mock = mock(Observer.class);
Observer mock1 = mock(Observer.class);
obs.subscribe(mock);
obs.subscribe(mock1);
subject.onNext(1);
Could you suggest a fix?
Thanks
P.S. Right now I'm using cache(1) to fix the issue but I'm not sure if it's ok to do it this way. Moreover, I can't just quite understand why a single stream of execution would depend on amount of observers attached. Can you comment on that?
You are already sort of using it, you need either publish() + connect() or publish().refCount() if you want to make the value shareable by multiple observables. The first case lets you control when to actually make the Observable go hot, while the second will go live as soon as you subscribe the first time. RxJS also has share which wraps publish().refCount() not sure if RxJava has that as well.
PublishSubject<Integer> subject = PublishSubject.create();
Observable<String> obs = subject.asObservable().flatMap(integer -> {
// this code runs for each observer, which is twice in this case
return Observable.just(String.valueOf(integer));
}).publish().refCount();
Observer mock = mock(Observer.class);
Observer mock1 = mock(Observer.class);
obs.subscribe(mock);
obs.subscribe(mock1);
subject.onNext(1);

Observable that wraps FromEventPattern while caching the most recent event for new subscribers

I have created an observable by using Observable.FromEventPattern. Let's call it fromEvents.
I want to create another observable that wraps fromEvents. We'll call this 2nd observable wrapper.
When wrapper is subscribed to it should:
Publish the most recent item from fromEvents if any.
Publish the rest of items coming from fromEvents
Obviously wrapper will need to maintain a subscription to fromEvents so that it always has access to the most recent event.
I have tried various combinations of Replay, Publish, PublishLast, Observable.Defer and I'm never quite getting the results I'm looking for.
I'm certain Rx has operators that will meet my needs, I'm just unsure of exactly how to put everything together, being the newb that I am.
I think I've been able to get what I want by doing this:
Events = Observable.FromEventPattern(...).Replay(1).RefCount();
// contrived example
// in my real app the subscription lives for a specific duration
// and Events is exposed as a readonly property
using(Events.Subscribe())
{
// get most recent or wait for first
var e = Events.FirstAsync().Wait();
}
Example using the Publish overload that uses a BehaviorSubject behind the scenes to keep track of the most recent event.
var fromEvents = Observable.FromEventPattern(...);
var published = fromEvents.Publish(null);
// subscribe to this one
var wrapper = published.Where(e => e != null);
// start collecting values
var subscription = published.Connect();
wrapper.Subscribe(...);