问题
I have a few observables. And I need to know which one triggered the subscribe.
Observable.combineLatest(
this.tournamentsService.getUpcoming(),
this.favoriteService.getFavoriteTournaments(),
this.teamsService.getTeamRanking(),
(tournament, favorite, team) => {
//what triggered combinelatest to run?
}).subscribe()
回答1:
Short answer is: You don't know. You could implement some workaround, however this is really ugly and I would recommend rethinking the usecase why you need this and maybe if you can change the architecture. Also keep in mind, that the first execution of your function will be after all three observables have emitted at least 1 value.
Anyway - a possible workaround could be:
let trigger = "";
Observable.combineLatest(
this.tournamentsService.getUpcoming().do(() => trigger = "tournament"),
this.favoriteService.getFavoriteTournaments().do(() => trigger = "favTournament"),
this.teamsService.getTeamRanking().do(() => trigger = "teamRanking"),
(tournament, favorite, team) => {
console.log(`triggered by ${trigger}`);
}).subscribe();
If you want to execute a specific operation based on which observable triggered, you should make use of each observable and utilize them as individual triggers, that switch to a combined trigger, it might be slightly more code but it is much cleaner and you will not end up in an ugly if/else, switch/case-mess with some hacky workarounds - plus you will have even have the oportunity to use the async
-pipe instead of manually subscribing to everything and updating local variables (which is a bad practice anyways):
Here is some example code of how this could look like:
let upcoming$ = this.tournamentsService.getUpcoming();
let favorite$ = this.favoriteService.getFavoriteTournaments();
let rankings$ = this.teamsService.getTeamRanking();
let allData$ = Observable.combineLatest(
upcoming$, favorite$, rankings$,
(tournament, favorite, team) => {
return {tournament, favorite, team};
}
);
// initial call -> this SHOULD be redundant,
// but since I don't know your code in detail
// i've put this in - if you can remove it or not
// depends on the order your data coming in
allData$
.take(1)
.do(({tournament, favorite, team}) => {
this.displayMatches(...);
this.sortByFavorites(...);
this.fillWithRanking(...);
})
.subscribe();
// individual update triggers
upcoming$
.switchMapTo(allData$.take(1))
.do(({tournament, favorite, team}) => this.displayMatches(...))
.subscribe();
favorite$
.switchMapTo(allData$.take(1))
.do(({tournament, favorite, team}) => this.sortByFavorites(...))
.subscribe();
rankings$
.switchMapTo(allData$.take(1))
.do(({tournament, favorite, team}) => this.fillWithRanking(...))
.subscribe();
回答2:
You could use the scan operator to compare the emitted values with any previously emitted values and could include additional data indicating whether or not components of the combined observable have actually changed. For example:
let combined = Observable
.combineLatest(
this.tournamentsService.getUpcoming(),
this.favoriteService.getFavoriteTournaments(),
this.teamsService.getTeamRanking()
)
.scan((acc, values) => [
...values,
acc[0] !== values[0],
acc[1] !== values[1],
acc[2] !== values[2]
], []);
combined.subscribe(
([tournament, favorite, team, tournamentChanged, favoriteChanged, teamChanged]) => {
console.log(`tournament = ${tournament}; changed = ${tournamentChanged}`);
console.log(`favorite = ${favorite}; changed = ${favoriteChanged}`);
console.log(`team = ${team}; changed = ${teamChanged}`);
}
);
回答3:
A quite clean and "rx"-way of achieving this is by using the timestamp operator http://reactivex.io/documentation/operators/timestamp.html
Example code
sourceObservable
.pipe(
timestamp(), // wraps the source items in object with timestamp of emit
combineLatest( otherObservable.pipe( timestamp() ), function( source, other ) {
if( source.timestamp > other.timestamp ) {
// source emitted and triggered combineLatest
return source.value;
}
else {
// other emitted and triggered combineLatest
return other.value;
}
} ),
)
If more than two observables are involved in the combineLatest()
sorting them by timestamp would enable to detect which one triggered the combineLatest()
.
回答4:
I am using RxJava in Flutter and I want to combine 12 different observables using the operator combineLatest.
I saw a function prototype that takes a list of observables and an implementation. but I am not sure how to do this, I am having trouble implementing the call method. Please check my code and do the needful.
Stream> get cities => _citiesController.stream;
Stream get city => _cityController.stream;
Stream get agentcity => _agentcityController.stream;
Stream get userpackages => _packagesController.stream;
Stream get email => _emailController.stream.transform(validateEmail);
Stream get firstName => _firstNameController.stream.transform(validateFirstName);
Stream get lastName => _lastNameController.stream.transform(validateLastName);
Stream get mobileNumber => _mobileNumberController.stream.transform(validateMobile);
Stream get dob => _dobController.stream.transform(validatedob);
Stream get appointmentdate => _appointmentdateController.stream.transform(validateappointmentDate);
Stream get pincode => _pincodeController.stream.transform(validatePincode);
Stream get gender => _genderController.stream;
Stream get address => _addressController.stream.transform(validateAddress);
Stream get agentname => _agentnameController.stream.transform(validateAgentName);
Stream get validSubmission => Observable.combineLatest9(
email,
firstName,
mobileNumber,
pincode,
dob,
address,
agentname,
_genderController.stream,
_cityController.stream,
_agentcityController.stream,
_packagesController.stream,
_appointmentdateController.stream,
(e, f, m, p, d, a, an, g, c, ac, pc, ad) => true,
);
Please let me know how to use combineLatest in my Flutter code.
来源:https://stackoverflow.com/questions/40804674/what-triggered-combinelatest