这可能是一个菜鸟问题,但我可以找到它的参考。
我有两个组件放在不同的地方,每个组件使用一个服务来查询端点并获取一些数据(例如用户配置文件)。
该服务返回一个observable,我需要observable是唯一的或者至少要发出一个唯一的请求。
// Service, shared across multiple components
@Injectable()
export class SomeService {
getData(): Observable<DataModel> {
return this._http.get<DataResponse>('/some-route').pipe(
map((response: DataResponse) => this.handleResponse(response)),
share() // is this right ?
);
}
}
// Component requesting data
@Component({ selector: '...', ... })
export class FirstComponent implements OnInit {
constructor(private _service: SomeService) { }
ngOnInit() {
this._service.getData().subscribe(
data => {
console.log(data);
}
);
}
}
// Another component requesting the same data
@Component({ selector: '...', ... })
export class SecondComponent implements OnInit {
constructor(private _service: SomeService) { }
ngOnInit() {
this._service.getData().subscribe(
data => {
console.log(data);
}
);
}
}
该服务工作,它获取数据,但请求发送两次,我只想要发送一个请求。组件同时存在(假设一个在顶部,第二个在屏幕的底部)。所以他们同时提出请求。
有没有办法服务只发送一个请求。
而BTW,第一个请求的状态为200,第二个请求的状态为304。
谢谢。
可能解决方案
到目前为止,我通过添加Service变量来管理
private _observable: Observable<DataModel>;
然后在获取数据时
getData(): Observable<DataModel> {
if (!this._observable) {
this._observable = this._http.get<DataResponse>('/some-route').pipe(
map((response: DataResponse) => this.handleResponse(response)),
// HERE IS THE TRICK
publishLast(),
refCount()
)
}
return this_observable;
}
诀窍是使用publishLast和refCount
有更好的方式/想法吗?
看看我的库ngx-rxcache。它简化了国家的管理。
https://github.com/adriandavidbrand/ngx-rxcache
@Injectable()
export class SomeService {
private dataCache = this.cache.get<DataModel>({
id: 'some uniquie id',
load: true,
construct: () => this.http.get<DataResponse>('/some-route').pipe(
map((response: DataResponse) => this.handleResponse(response))
)
});
data$ = this.dataCache.value$;
constructor(cache: RxCacheService, http: HttpClient) {}
}
然后,您可以访问服务上的数据
this.service.data$;
https://medium.com/@adrianbrand/angular-state-management-with-rxcache-468a865fc3fb
您可以轻松地将请求分组到一个Observable中,该Observable将在使用forkJoin
Operator完成所有请求时解析
这是一个例子
public requestDataFromMultipleSources(): Observable<any[]> {
let response1 = this.http.get(requestUrl1);
let response2 = this.http.get(requestUrl2);
let response3 = this.http.get(requestUrl3);
// Observable.forkJoin (RxJS 5) changes to just forkJoin() in RxJS 6
return forkJoin([response1, response2, response3]);
}
在您的示例中,您应该在父组件中发出请求。然后将结果注入子组件
你可以使用shareReplay,它会将来自source observable的事件重播给所有订阅者并确保你只共享最后一个结果
shareReplay(1)
所以你的代码看起来像这样
getData(): Observable<DataModel> {
return this._http.get<DataResponse>('/some-route').pipe(
map((response: DataResponse) => this.handleResponse(response)),
shareReplay(1)
);
}
我发现以下模式对此有效:
@Injectable()
export class SomeService {
myDataObservable$: Observable<DataModel>;
constructor( ) {
this.myDataObservable$ = this.getData().pipe(shareReplay());
}
getData(): Observable<DataModel> {
return this._http.get<DataResponse>('/some-route').pipe(
map((response: DataResponse) => this.handleResponse(response))
);
}
}
使用此模式,在至少一个组件中调用myDataObservable $上的subscribe之前,不会发送http请求。在第一个组件调用subscribe之后,所有后续订阅都将使用已存在的值,因此您将不会有多个http请求。