Is there a way to know if an Rx.Observable has completed AFTER the fact, i.e. after onCompleted call on the subscribers? This would be similar to the has_next method for iterators. I could not find anything in the doc (or elsewhere) on that subject.
For a cold observable, the question would not make so much sense, as one can resubscribe at will, and the observable will be started anew. For a time-limited hot observable, one could imagine the edge case of being passed a reference to that hot observable, and subscribing for its values, never receiving anything and not even knowing that nothing will ever be received.
Evers obserbable or observer have the property isStopped. This is eighter true if it is completed or error was thrown or it is false which means it it still active.
Here is the answer I got from another channel (quoted below).
The "usual" channels of creating a hot observable, such as creating a subject or using .publish() will "replay" the terminal message (i.e., onError or onCompleted), but there is no such guarantee in general. I would argue though that any hot sequence that did not have this terminal message replay violates the contract of an observable, and appropriate bugs should be filed.
Related
I am having two http requests where the second one (Log request) should be subscribed after the first one (Order request) emits a value and I do some logic that should not be blocked by the Log request and the result of log request is ignored.
As I understand that tap is
Used to perform side-effects
https://rxjs.dev/api/operators/tap
and since I assume Log request and its response here is a side-effect to the Order request, is it bad practice to subscribe inside tap? Is there a more slick and RxJS way of handling this?
const order = of('2- created order').pipe(
delay(100),
tap(console.log)
);
const log = of('4- logged info to log server').pipe(
delay(500),
tap(console.log)
);
console.log('1- started creating order');
order
.pipe(tap(() => log.subscribe()))
.subscribe(() => console.log("3- didn't wait for log server"));
StackBlitz
Yes, it definitely is bad practice.
You're right that tap is there for side effects but those should not involve other streams, they should be simple side effects like assigning variables or console logging and stuff.
The issue is that you generally do not want to subscribe inside a subscribe on inside the pipe because doing so makes for very unpredictable and difficult to maintain code.
For example your subscribe inside the tab looks innocuous enough, but imagine if you were listening to a continuous stream of data, how many subscriptions would you have? would you care to track them all to unsubscribe, wouldn't that end up quite difficult to understand/debug, etc...
The problem with your code is that you are somewhat thinking in an imperative way (something like "do this and then that, and then...") instead of thinking in terms of streams.
So basically in my opinion, instead of thinking something like "how do I do this before that?" you should be thinking about how you handle the stream and the order of operations you can perform on it.
In your case, is there any reason why you'd want to print the third message inside the subscribe and not in the pipe?
Why not just doing the following?
order
.pipe(
tap(() => console.log("3- didn't wait for log server")),
switchMap(() => log)
)
.subscribe();
(like here: https://stackblitz.com/edit/rxjs-aace8i?file=index.ts)
If I may, I would like to analyse your question...
Starting with
I am having two http requests where the second one (Log request)
should be subscribed after the first one (Order request) emits a value
that just seems a simple case of having an initial observable (Order) and needing to use a mapping operator to move to a different one (Log), I assumed that you want to discard the first and move to the second so I chose switchMap (alternatively you could use concatMap or mergeMap)
Then we get to:
and I do some logic that should not be blocked by the Log request and
the result of log request is ignored.
since we already thought of how to handle the 2 observables, if we read your sentence it really spells out that we just want a side effect to occur between the first and second observable, and it ignores the streams' values anyways, so it clearly calls for a simple tap
I am sorry for the rather long message I hope it does not sound too pedantic :P
What I basically wanted to say is that you should always look at your streams and sort of think how to fit all together in accordance to rxjs programming style and what you need, and not whether some ways of doing something is acceptable or not, as that makes me realy thing that you already had suspicions on whether it not being the best solution.
As #martin mentions in the comment, it's generally bad to subscribe inside a pipe (not specifically tap, but any operator) because there's no way handle cleaning up subscriptions.
Generally, it's preferred to use one of the "Higher-Order Mapping Operators" because they handle subscribing, emitting, and unsubscribing from your observable.
Is there a more slick and RxJS way of handling this
Not sure if this would be considered "slick" or not :-), but I think it gives a nice separation of concerns if a Subject is used as a dedicated stream of log messages; then create a single subscription to have your server logging logic executed:
const logMessage$ = new Subject<string>();
logMessage$
.pipe(mergeMap(logToServer))
.subscribe();
Then in your other code, instead of subscribing, you can call logMessage$.next() to trigger the server logging logic without impeding the flow of your order stream:
order.pipe(tap(o => logMessage$.next(o)));
Here's an updated StackBlitz.
I'm looking for information about whether promises chains are guaranteed to be completed before being garbage collected if the reference is lost. I'm executing a call to my API within a React useEffect hook, but am not clear about what happens if one of the dependencies change and the useEffect hook is re-executed while the promise is still pending.
A contrived example:
const useApiFetch = (query, myVariable) => {
const client = useClient();
useEffect(()=>{
client
.query(query)
.then(() => console.log('inside thenable'))
.catch(() => console.log('inside catch');
},[variable, client]);
}
Questions:
What happens if myVariable changes and useEffect is re-executed while the promise is pending? Will the promise complete before being garbage collected?
What about if the component that is consuming this hook is re-rendered or removed from the virtual DOM?
If I don't have a cleanup function, is there any chance of a memory leak?
I may not be the perfect one but from my usage with react and functional components i will try to answer these.
When your dependencies for the hook changes, the function inside is re invoked. That means in your case a second api call. What this in turn results in may depend on api response time, client device, internet speed and way you handle these.
For example, if you are rendering something in the promise success for example a Text. What happens is once you UI renders the first data that it gets, like if you are setting state or something. Aa soon as the next api call resolves the UI again re-renders to reflect that change.
taking your example code. If you change the dependency "variable" three times, you get three "inside thenable" if promise resolves or else the catch console.log.
Note: If for any reason you api process takes some time for example a large query, then you may not be able to tell which api call will get resolved first. I had this issue when i implemented a text based onChange search using api. A good solution will be to debounce your api calls to limit no of calls and also to cancel unwanted calls.
If you have setStates that is tied to your promise resolution/rejection and you haven't properly handled the unmount condition. React will show you a warning stating the same. Something that means "You have a state change happening in an unmounted component/screen". This can lead to memory leaks if left unchecked.
Hope you get some point out of this. I am not a pro at this, these are somethings that i found while working with React.
Is it safe to assume that RxJS will trigger the next function of each of its observers in the order they have subscribed. I have a class with a public propery of BehaviorSubject. The first subscription made to it will be from with in the class' constructor. I would like to make sure that the next of this private subscription works before any other's.
Practically speaking, yes, this is safe; the implementation of the Subject class (from which BehaviorSubject inherits) always processes subscriptions in the order they are taken. While I've not seen a guarantee from the rxjs team that this will always be the case, I imagine changing this would break a lot of code (mine included).
Strictly speaking, no, no guarantee is made regarding subscription processing order. This goes back to Rx under .NET, when the team tried to align the subscription behavior with that of multicast delegates (you can find a good explanation from Bart De Smet at https://social.msdn.microsoft.com/Forums/en-US/ac721f91-4dbc-40b8-a2b2-19f00998239f/order-of-subscriptions-order-of-observations?forum=rx).
I have run across scenarios before where the "process in subscription order" hasn't suited me, and I've needed to take direct control. In this case, I've used a simple function to turn one observable into two, one of which is guaranteed to be notified before the other. You could use a similar method to avoid making the assumption that subscriptions will always be processed in order, though I personally do not think it's necessary. If interested, you can find details here: RxJs: Drag and Drop example : add mousedragstart
In terms of behaviorSubject, and subjects in general, they are "Hot" Observables that produce and consume values. You can assume that the next function will always trigger so long as nothing calls the observer.complete() method.
The first subscription you have will set and initialize the state (assumption here) and so every subsequent subscriber will be able to hook in to that subscription and ascertain the next(value) emissions.
Hope this helps.
Something I noticed the other day. I was subscribing to the Actions stream inside #ngrx/effects. I noticed (an issue for me) where a component, which subscribes to Actions late, receives the last dispatched action. This I can see is because the dispatcher inside #ngrx/store is a BehaviourSubject and quoting the RxJS docs:
Rx.BehaviorSubject class
Represents a value that changes over time. Observers can subscribe to the subject to receive the last (or initial) value and all subsequent notifications.
Unfortunately, I'd like to subscribe to the actions stream without retrieving the last value. It creates problems for me like showing error messages when a user returns to a page.
The difference between BehaviorSubject and Subject (which does it the way I'd like) is demo'd here:
https://codepen.io/anon/pen/zwgype
Is there any way of achieving this?
You can skip the first value with the 'skip' operator:
someBehaviorSubject.skip(1)
I've started playing with RxJS5, and now see that there is no longer a shareReplay method.
It's quite possible that I often misused shareReplay in RxJS4, but now I'm struggling to get the behaviour that I want, i.e:
Create an observable
Subscribe to the observable, and the observable produces a value
Subscribe to the observable a second time, and I get the same first value
Observable produces a second value, and both subscriptions get the second value
How do I implement this with RxJS5?
In general I think I understand the RxJS operators quite well, but the whole cold, hot, publish, connect is rather unclear to me. Is there a good reference that shows how to find what kind of observable I have, so that I can find out in a logical manner why a subscribe is not getting values, or why an observable is being executed multiples times?
EDIT
Happy news, shareReplay() is back in RxJS 5.4.0:
Changelog: https://github.com/ReactiveX/rxjs/blob/892700dd4f5d5e5f9ae9276ede32208f4390c5e9/CHANGELOG.md#540-2017-05-09
Barebones documentation: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-shareReplay
That question is best answered by members who participate in Rxjs5, but here is my take:
shareReplay is the multicast operator with a ReplaySubject, followed by a refCount. So I would bet that publishReplay(x).refCount() should be quite close to the shareReplay behaviour. In any case, publishReplay already gives you all the points you mentioned. The refCount adds the unsubscription when there is no more observers (refCount decreased to 0).
you can have a look at the specs here http://reactivex.io/rxjs/test-file/spec-js/operators/publishReplay-spec.js.html. See line 127 onwards var replayed = source.publishReplay(1).refCount();, that should be equivalent to your shareReplay(1).
About the rest of your question:
I think we all want that good reference that shows how to find what kind of observable I have.... There are many places, including Rxjs4 documentation where you find explanations about hot and cold observables.
Here, and here are some examples of resources.
Follows my own present understanding of the matter:
subjects are hot (mostly anyways, as you could argue that a replay subject has a behaviour closer to than of a cold observable)
all observables are cold, unless made explicitly otherwise.
among the explicit ways to make a cold observable hot, you have the multicast operator and its derivatives share, publish, shareReplay etc. Those operators internally all involve subjects.
Note that it does not have to be visible to you that those operators were used. But in that case, the API or documentation should explicitly tell you. For instance, Rx.Observable.fromEvent('input','click') is hot. You can see in its implementation that there is a share somewhere.
to the hot/cold dichotomy you have to add the connectable kind which till it is connected, is neither hot nor cold.
defer always give rise to a cold observable.
lastly some operators do not change the nature of the observable, but do create hot observables internally and pass them on in their stream. That is the case for instance of groupBy. op1.op2.groupBy is cold, but it will emit hot observables as values in the resulting stream. In those cases, only the documentation (if any) can help you find out. Otherwise, the source code, and the test specs. Or asking on SO.