Angular,使用具有 BehaviorSubject 问题的 Observables
Angular, consuming Observables with BehaviorSubject issues
我创建了一堆代码,试图找出正确使用共享数据的实际方法。
我有一个服务正在使用来自其他服务的数据,并返回一个计算接口。
(IDriverProfile)
我面临的挑战是我想一次使用所有服务。我最初为此使用了 forkJoin,效果很好。当我尝试将数据更改为从 BehaviorSubject 中提取作为 Observable 的那一刻,事情就坏了。
我很确定我在 combineLatest 上做错了什么,但是有更好的方法来解决这个问题吗?这似乎是一个相当基本的用例:
- 筛选数据的查询服务
- 根据一些共享数据集改变数据
- 合成消耗品
- 组件使用 DriverProfileService
DriverProfile.Service.ts(尝试 1)
由于 forkJoin 未从 behaviorSubject 完成而失败。
getDriverProfile(data:IDriverData): Observable<IDriverProfile>{
let driverStandings:IDriverStanding[] = [];
let driverQualifying:IQualifying[] = [];
let driverResults:IResult[] = [];
let careerStats:IDriverCareerStats;
let SeasonData:IDriverSeasonData[]=[];
let profile:IDriverProfile = {
driverData: data,
seasonsData: SeasonData,
careerStats: careerStats
};
// start forkJoin (works if all observables not utilizing shared data)
forkJoin({
QualyTask: this.qualifyService.getDriverQualifyingLaps(data.driver),
StandingsTask: this.driverStandingsService.getDriverStandings(data.driver),
ResultsTask: this.resultService.getDriverResults(data.driver),
RaceTask: this.raceService.getAllRaces(),
statusTask: this.statusService.status$,
teamsTask: this.teamsService.getAllConstructors()
}).subscribe(({QualyTask, StandingsTask, ResultsTask, RaceTask, statusTask, teamsTask})=>{
driverQualifying = QualyTask;
driverStandings = StandingsTask;
driverResults = ResultsTask;
let races = RaceTask;
let allStatus = statusTask;
let teams = teamsTask;
console.log('all status',allStatus);
let results = this.getResults(driverResults, races, driverStandings, allStatus, teams);
//console.log("results", results);
// calc career stats
profile.seasonsData = results.seasons;
profile.careerStats = results.stats;
});
console.log("profile", profile);
return of(profile);
}
DriverProfile.Service.ts(尝试 2 CombineLatest)
不确定为什么会失败?
getDriverProfile(data:IDriverData): Observable<IDriverProfile>{
// this section is for trying combineLatest (broken)
let task1 = this.qualifyService.getDriverQualifyingLaps(data.driver);
let task2 = this.driverStandingsService.getDriverStandings(data.driver);
let task3 = this.resultService.getDriverResults(data.driver);
let task4 = this.raceService.getAllRaces();
let task5 = this.statusService.status$;
let task6 = this.teamsService.getAllConstructors();
const combine$ = combineLatest(task1, task2, task3, task4, task5, task6,
(t1,t2,t3,t4,t5,t6)=> {
let results = this.getResults(t3, t4, t2, t5, t6);
return <IDriverProfile> {
driverData: data,
seasonsData: results.seasons,
careerStats: results.stats
}
});
return combine$;
}
Status.Service.ts
private readonly _StatusSource = new BehaviorSubject<IStatus[]>([]);
readonly status$ = this._StatusSource.asObservable();
constructor(private httpClient:HttpClient) {
this.loadInitialData();
}
loadInitialData() {
this.httpClient.get<IStatus[]>("assets/data/status.json").subscribe(x => {
//console.log('status load', x);
this._setStatus(x);
},
err => console.log("Error loading Status")
);
}
getStatus(): IStatus[] {
return this._StatusSource.getValue();
}
private _setStatus(status: IStatus[]): void {
this._StatusSource.next(status);
this._StatusSource.complete();
}
正如您提到的第 4 步:“组件消耗 DriverProfileService”。
我假设正在您的一个组件中订阅该方法
DriverProfile.Service.ts 更新方法如下:
// Assuming everything within the combine latest call are observables.
getDriverProfile(data:IDriverData): Observable<IDriverProfile> {
return Observable.combineLatest(
this.qualifyService.getDriverQualifyingLaps(data.driver),
this.driverStandingsService.getDriverStandings(data.driver),
this.resultService.getDriverResults(data.driver),
this.raceService.getAllRaces(),
this.statusService.getStatusSource(),
this.teamsService.getAllConstructors()
).map((t1,t2,t3,t4,t5,t6) => {
// I assume getResults is not an observable, it just transforms data or something.
let results = this.getResults(t3, t4, t2, t5, t6);
return <IDriverProfile> {
driverData: data,
seasonsData: results.seasons,
careerStats: results.stats
}
});
}
至于你的Status.Service.ts让我们保持简单:
// Declare your subject and set value to empty array
private statusSource = new BehaviorSubject<IStatus[]>([]);
// Contructor calling the method to get data initially
constructor(private httpClient:HttpClient) {
this.loadInitialData();
}
loadInitialData() {
this.httpClient.get<IStatus[]>("assets/data/status.json")
.subscribe(statusSource => {
this.setStatusSource(statusSource);
},(error) => console.log(error));
}
// Gets the status source
getStatusSource(): Observable<IStatus[]> {
return this.statusSource.asObservable();
}
// Sets the status source
public setStatusSource(statusSource: IStatus[]): void {
this.statusSource.next(statusSource);
}
我创建了一堆代码,试图找出正确使用共享数据的实际方法。
我有一个服务正在使用来自其他服务的数据,并返回一个计算接口。 (IDriverProfile)
我面临的挑战是我想一次使用所有服务。我最初为此使用了 forkJoin,效果很好。当我尝试将数据更改为从 BehaviorSubject 中提取作为 Observable 的那一刻,事情就坏了。
我很确定我在 combineLatest 上做错了什么,但是有更好的方法来解决这个问题吗?这似乎是一个相当基本的用例:
- 筛选数据的查询服务
- 根据一些共享数据集改变数据
- 合成消耗品
- 组件使用 DriverProfileService
DriverProfile.Service.ts(尝试 1)
由于 forkJoin 未从 behaviorSubject 完成而失败。
getDriverProfile(data:IDriverData): Observable<IDriverProfile>{
let driverStandings:IDriverStanding[] = [];
let driverQualifying:IQualifying[] = [];
let driverResults:IResult[] = [];
let careerStats:IDriverCareerStats;
let SeasonData:IDriverSeasonData[]=[];
let profile:IDriverProfile = {
driverData: data,
seasonsData: SeasonData,
careerStats: careerStats
};
// start forkJoin (works if all observables not utilizing shared data)
forkJoin({
QualyTask: this.qualifyService.getDriverQualifyingLaps(data.driver),
StandingsTask: this.driverStandingsService.getDriverStandings(data.driver),
ResultsTask: this.resultService.getDriverResults(data.driver),
RaceTask: this.raceService.getAllRaces(),
statusTask: this.statusService.status$,
teamsTask: this.teamsService.getAllConstructors()
}).subscribe(({QualyTask, StandingsTask, ResultsTask, RaceTask, statusTask, teamsTask})=>{
driverQualifying = QualyTask;
driverStandings = StandingsTask;
driverResults = ResultsTask;
let races = RaceTask;
let allStatus = statusTask;
let teams = teamsTask;
console.log('all status',allStatus);
let results = this.getResults(driverResults, races, driverStandings, allStatus, teams);
//console.log("results", results);
// calc career stats
profile.seasonsData = results.seasons;
profile.careerStats = results.stats;
});
console.log("profile", profile);
return of(profile);
}
DriverProfile.Service.ts(尝试 2 CombineLatest)
不确定为什么会失败?
getDriverProfile(data:IDriverData): Observable<IDriverProfile>{
// this section is for trying combineLatest (broken)
let task1 = this.qualifyService.getDriverQualifyingLaps(data.driver);
let task2 = this.driverStandingsService.getDriverStandings(data.driver);
let task3 = this.resultService.getDriverResults(data.driver);
let task4 = this.raceService.getAllRaces();
let task5 = this.statusService.status$;
let task6 = this.teamsService.getAllConstructors();
const combine$ = combineLatest(task1, task2, task3, task4, task5, task6,
(t1,t2,t3,t4,t5,t6)=> {
let results = this.getResults(t3, t4, t2, t5, t6);
return <IDriverProfile> {
driverData: data,
seasonsData: results.seasons,
careerStats: results.stats
}
});
return combine$;
}
Status.Service.ts
private readonly _StatusSource = new BehaviorSubject<IStatus[]>([]);
readonly status$ = this._StatusSource.asObservable();
constructor(private httpClient:HttpClient) {
this.loadInitialData();
}
loadInitialData() {
this.httpClient.get<IStatus[]>("assets/data/status.json").subscribe(x => {
//console.log('status load', x);
this._setStatus(x);
},
err => console.log("Error loading Status")
);
}
getStatus(): IStatus[] {
return this._StatusSource.getValue();
}
private _setStatus(status: IStatus[]): void {
this._StatusSource.next(status);
this._StatusSource.complete();
}
正如您提到的第 4 步:“组件消耗 DriverProfileService”。
我假设正在您的一个组件中订阅该方法DriverProfile.Service.ts 更新方法如下:
// Assuming everything within the combine latest call are observables.
getDriverProfile(data:IDriverData): Observable<IDriverProfile> {
return Observable.combineLatest(
this.qualifyService.getDriverQualifyingLaps(data.driver),
this.driverStandingsService.getDriverStandings(data.driver),
this.resultService.getDriverResults(data.driver),
this.raceService.getAllRaces(),
this.statusService.getStatusSource(),
this.teamsService.getAllConstructors()
).map((t1,t2,t3,t4,t5,t6) => {
// I assume getResults is not an observable, it just transforms data or something.
let results = this.getResults(t3, t4, t2, t5, t6);
return <IDriverProfile> {
driverData: data,
seasonsData: results.seasons,
careerStats: results.stats
}
});
}
至于你的Status.Service.ts让我们保持简单:
// Declare your subject and set value to empty array
private statusSource = new BehaviorSubject<IStatus[]>([]);
// Contructor calling the method to get data initially
constructor(private httpClient:HttpClient) {
this.loadInitialData();
}
loadInitialData() {
this.httpClient.get<IStatus[]>("assets/data/status.json")
.subscribe(statusSource => {
this.setStatusSource(statusSource);
},(error) => console.log(error));
}
// Gets the status source
getStatusSource(): Observable<IStatus[]> {
return this.statusSource.asObservable();
}
// Sets the status source
public setStatusSource(statusSource: IStatus[]): void {
this.statusSource.next(statusSource);
}