我有几个可观察者。我需要知道哪一个触发了订阅。
Observable.combineLatest(
this.tournamentsService.getUpcoming(),
this.favoriteService.getFavoriteTournaments(),
this.teamsService.getTeamRanking(),
(tournament, favorite, team) => {
//what triggered combinelatest to run?
}).subscribe()
答案 0 :(得分:4)
简短的回答是:你不知道。 你可以实现一些解决方法,但这真的很难看,我建议你重新考虑用法为什么需要这个,也许你可以改变架构。 还要记住,在所有三个observable都发出至少1个值之后,你的函数的第一次执行将会发生。
无论如何 - 可能的解决方法可能是:
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();
如果你想根据触发的observable执行一个特定的操作,你应该使用每个observable并将它们作为单独的触发器使用,切换到组合的触发器,它可能稍微多一些代码,但它更清晰,你不会在一个丑陋的if / else,switch / case-mess中遇到一些hacky变通方法 - plus 你甚至会有机会使用async
- 管道而不是手动订阅所有内容并更新局部变量(无论如何这都是一种不好的做法):
以下是一些示例代码:
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();
答案 1 :(得分:4)
您可以使用scan
运算符将发出的值与任何先前发出的值进行比较,并且可以包含指示组合的observable的组件是否实际已更改的其他数据。例如:
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}`);
}
);
答案 2 :(得分:3)
通过使用时间戳运算符http://reactivex.io/documentation/operators/timestamp.html
,实现这一点非常简洁和“rx”示例代码
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;
}
} ),
)
如果combineLatest()
中有两个以上的可观察对象按时间戳排序,则可以检测哪一个触发了combineLatest()
。
答案 3 :(得分:1)
我正在Flutter中使用RxJava,我想使用操作符CombineLatest组合12种不同的可观察对象。
我看到了一个函数原型,该原型带有一个可观察对象列表和一个实现。但是我不确定该怎么做,我在实现call方法时遇到了麻烦。请检查我的代码并做必要的事情。
Stream>获取城市=> _citiesController.stream;
Stream get city => _cityController.stream;
Stream get agentcity => _agentcityController.stream;
Stream get userpackages => _packagesController.stream;
流获取电子邮件=> _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);
流获取约会日期=> _appointmentdateController.stream.transform(validateappointmentDate);
Stream get pincode => _pincodeController.stream.transform(validatePincode);
流获取性别=> _genderController.stream;
流获取地址=> _addressController.stream.transform(validateAddress);
Stream get agentname => _agentnameController.stream.transform(validateAgentName);
流获取有效的提交=> 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,
);
请让我知道如何在Flutter代码中使用CombineLatest。
答案 4 :(得分:0)
解决此问题的更好方法是使用可区分的联合类型。如果您的语言没有内置可区分联合,您可以通过将构造函数设为私有并公开 n
可为空的公共静态属性来创建一个联合,每个可观察对象一个。用 C# 编写这个,因为我更喜欢这种语言,但它应该很容易翻译。注意可为空的字符串。如果您的语言不支持可空值,请使用其他一些机制来指示是否设置了值。
private class DiscriminatedUnion
{
private DiscriminatedUnion(string? property1, string? property2)
{
Property1 = property1;
Property2 = property2;
}
public string? Property1 { get; }
public string? Property2 { get; }
public static DiscrimintatedUnion FromObservable1(string property1)
{
return new DiscriminatedUnion(property1, null);
}
public static DiscrimintatedUnion FromObservable2(string property2)
{
return new DiscriminatedUnion(null, property2);
}
}
private IObservable<DiscriminatedUnion> CreateCombination()
{
var firstObservable = tournamentsService
.getUpcoming()
.Select(x => DiscriminatedUnion.FromObservable1(x));
var secondObservable = favoriteService
.getFavoriteTournaments()
.Select(x => DiscriminatedUnion.FromObservable2(x));
return Observable
CombineLatest(firstObservable, secondObservable);
}
所以现在你可以质疑从 CreateCombination()
返回的可区分联合,哪个 observable 发出了一个值。