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)
Related
I have used behaviourSubject in shared service to get the current value while clicking a button.It is working as expected but some times the api call inside the subscribe block of behavioursubject hits multiple times.
what will be the issue??
There can be any of the following reasons:
This happens, when you subscribe to BehaviorSubject in a block of code that executes multiple times. Example if you subscribe in ngAfterViewChecked life cycle hook of angular component that executes multiple times.
You never unsubscribed but every time app loads the component, subscribe your behaviour subject.
Subscriber of BehaviorSubject always executes at least once, because BehaviorSubject requires a default argument when created and emits the passed default argument at least once, if you call .next() method only once on the instance of BehaviorSubject, Subscriber will execute twice. 1st time for default value passed while creating instance of BehaviorSubject, 2nd time for the value you passed by calling .next method on the instance of BehaviorSubject.
Did I answer your question ?
If not, please provide the code snippet, so that we could understand the problem better.
I have a hot observable that emits messages. Currently I'm using publishReplay(1).refCount() so everyone subscribing will receive the last message. Now, the messages passing through May have a field containing a boolean to determine if it should be just passed through to all subscribers, or if it should be stored in the replay to be emitted to all new sebscribers too.
Has anyone any idea, how to achieve this usecase?
I implemented my own publishReplayConditionally and ConditionalReplaySubject. They additionally accept an expression as a parameter to decide if the value should be stored.
I am experiencing some interesting behaviour regarding a subscription on a collection's valueChanges.
Immediately after creating a doc, the collection's subscription is invoked, but instead of an array of many documents I am only receiving an array of size one - the single, newly created document.
After having a read through this (Firestore Docs | Get Realtime Updates) I am still slightly confused.
Local writes in your app will invoke snapshot listeners immediately. This is because of an important feature called "latency compensation." When you perform a write, your listeners will be notified with the new data before the data is sent to the backend.
Does this explain the behaviour I am seeing?
Here is a stackblitz demonstrating the problem. Just uncomment out the commented line in ngOnInit() and reload to see what I believe is expected behaviour.
I can solve this by either having an empty subscription listening to this collection elsewhere, or duplicating the take(1) subscription code directly before
Thats a good catch. Pretty sure you are right - valueChanges() as docs states:
The current state of your collection. Returns an Observable of data as
a synchronized array of JSON objects.
And as you found yourself:
Local writes in your app will invoke snapshot listeners immediately.
So this is what happens:
Your addPizza() is an async function. It sends request to backed to add new pizza. But it doesnt wait for anything and jumps to your second function - this.getPizzasAsyncAwait(). And because that local write invokes listener immediately, your Observable emits that value and broadcasts it. And since you also use Rxjs's take(1) - after that it unsubscribes. That also explains why take(2) brings all other records. You can move your getPizzasNormal() method to OnInit() and you'll receive the whole collection.
The firebase js sdk handles optimistically the add, before getting the collection values, the collection is not defined yet. Once you add a value the collection contains 1 value and then is updated by the server side values.
If you want to avoid getting this intermediate state when the collection values are set only from local changes, you can subscribe before start changes to be done before subscribing :
this.piazzaRef.add({
name: name,
addedAt: new Date().toISOString()
}).then(() => {
this.getPizzasAsyncAwait();
this.getPizzasNormal();
});
I updated your example here
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.
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.