Reputation: 83311
In my Angular app, I have a bunch of Observable
s that emit notifications when certain data changes. Sometimes, I'll run into a case where I need to notify several Observable
s about data changes in rapid succession:
// Subscribers for observable1 are immediately notified.
observable1.next(...)
// Subscribers for observable2 are immediately notified.
observable2.next(...)
This can sometimes cause annoying bugs, however. I frequently run into situations where the order in which Observable
s are notified can cause unexpected behavior. For example, the subscribers for observable1
might execute code that assumes the subscribers for observable2
have already been notified.
Basically, I am looking for a way to delay the emission of items to subscribers until the current Angular tick has completed. For example, something like:
observable1.next(...)
observable2.next(...)
// At the end of the current Angular tick, the subscribers
// for observable1 and observable2 are notified.
Or perhaps there is some other rxjs
operator that I could use to achieve something similar...
Upvotes: 2
Views: 4351
Reputation: 12247
This is a classic race condition: your subscribers to observable1
and observable2
claim to be independent, but they seem actually to be coupled.
I played with implementations of .delayWhen()
, but the only thing that seemed to guarantee that both are up to date before they are used given your current architecture is to .zip()
the two Observables at the source, emit the result, and to have your subscribers split them:
console.info('Waiting for Observables...');
const observable1 = Rx.Observable.of([1,2,3])
.delayWhen(() => Rx.Observable.timer(1000));
const observable2 = Rx.Observable.of(['a', 'b', 'c'])
.delayWhen(() => Rx.Observable.timer(500));
const merged = Rx.Observable.zip(observable1, observable2).share();
// Where you need the result from 1
merged.subscribe(
next => {
console.info("Subscriber 1");
console.info(next[0]);
}
);
// Where you need the result from 2
merged.subscribe(
next => {
console.info("Subscriber 2");
console.info(next[1]);
}
);
<script src="https://unpkg.com/@reactivex/rxjs@5.3.0/dist/global/Rx.min.js"></script>
Because it kind of is, but all we're doing is explicitly implementing a coupled state that is already coupled conceptually by the architecture.
The real solution is to somehow change the architecture so that they are not dependent (by, for example, changing the payload returned by whoever produces the two observable's data sets).
This also only works in this fairly trivial example where the total number of Observables is known and are in the same service. It quickly gets very complicated if these two conditions are exceeded.
The overall architecture is another question and outside this scope since we don't have insight into this.
Upvotes: 1