结合 Observable 和 ReplaySubject
Combine Observable with ReplaySubject
在我的项目中,我想使用 Observables 调用一个 api,然后借助 ReplaySubject 的强大功能,我想记住它的结果,这样当我重新访问该页面时,我不必调用再次 api。理想情况下,我会记住一定毫秒数的结果,我知道你可以在 ReplaySubject 中设置。
我知道的一个问题是订阅不能在组件上,因为当您再次访问页面时它会重新启动,因此需要使用服务文件。
首先,我有我的正常 http.service 文件,它应该没问题:
http.service.ts
getVenuesListViaPost(filter, searchObj): Observable<any> {
return this.http.post("api/venues/search"+filter, searchObj)
}
然后我有了实际显示数据的组件。这样应该没问题。
venues.component.ts
getData(page: number) {
this.listedAsyncData$ = this.replayApiService.replayVenueApi(page, this.name);
}
我在我的组件上使用异步管道,即:
venues.component.html
<tr *ngFor="let item of (listedAsyncData$ | async)?.items"><td>{{item.name}}</td></tr>
所以我认为问题出在我的 replayApiService 上,但我很困惑为什么这不起作用。
回放-api.service.ts
import { Injectable } from '@angular/core';
import { HttpService } from "./http.service";
import {ReplaySubject, tap} from 'rxjs';
@Injectable()
export class ReplayApiService {
private _rememberSource = new ReplaySubject<object>(1, 200000);
remember$ = this._rememberSource.asObservable();
constructor(private httpService: HttpService) { }
replayVenueApi(page, name) {
this.httpService.getVenuesListViaPost(`?pageno=${page}&pageSize=10`, { name }).pipe(
tap(res => this._rememberSource.next({
"items": res.body,
"totalPages": parseInt(res.headers.get('x-paging-pagecount'))
}))
).subscribe();
}
}
我可以看到网络调用是正确的,但是页面上没有显示结果。
我建议你重构 replayVenueApi
如下:
replayVenueApi(page, name) {
this.httpService.getVenuesListViaPost(`?pageno=${page}&pageSize=10`, { name }).pipe(
tap(res => this._rememberSource.next({
"items": res.body,
"totalPages": parseInt(res.headers.get('x-paging-pagecount'))
}))
).subscribe();
}
这不会实现您的“如果少于 20 秒就不要重复请求”,但这确实意味着您的 ReplaySubject 将发出。
在您的组件中,您需要使用 Observable,因为 replayVenuApi
没有 return 任何东西:
getData(page: number) {
this.listedAsyncData$ = this.replayApiService.remember$;
this.replayApiService.replayVenueApi(page, this.name);
}
对于计时器元素,一种可能的方法是存储时间戳并将其与每次调用 replayVenueApi()
的 Date.now()
进行比较。如果差异小于 20 秒,则您什么都不做。如果更多,你提出要求。
在我的项目中,我想使用 Observables 调用一个 api,然后借助 ReplaySubject 的强大功能,我想记住它的结果,这样当我重新访问该页面时,我不必调用再次 api。理想情况下,我会记住一定毫秒数的结果,我知道你可以在 ReplaySubject 中设置。
我知道的一个问题是订阅不能在组件上,因为当您再次访问页面时它会重新启动,因此需要使用服务文件。
首先,我有我的正常 http.service 文件,它应该没问题:
http.service.ts
getVenuesListViaPost(filter, searchObj): Observable<any> {
return this.http.post("api/venues/search"+filter, searchObj)
}
然后我有了实际显示数据的组件。这样应该没问题。
venues.component.ts
getData(page: number) {
this.listedAsyncData$ = this.replayApiService.replayVenueApi(page, this.name);
}
我在我的组件上使用异步管道,即:
venues.component.html
<tr *ngFor="let item of (listedAsyncData$ | async)?.items"><td>{{item.name}}</td></tr>
所以我认为问题出在我的 replayApiService 上,但我很困惑为什么这不起作用。
回放-api.service.ts
import { Injectable } from '@angular/core';
import { HttpService } from "./http.service";
import {ReplaySubject, tap} from 'rxjs';
@Injectable()
export class ReplayApiService {
private _rememberSource = new ReplaySubject<object>(1, 200000);
remember$ = this._rememberSource.asObservable();
constructor(private httpService: HttpService) { }
replayVenueApi(page, name) {
this.httpService.getVenuesListViaPost(`?pageno=${page}&pageSize=10`, { name }).pipe(
tap(res => this._rememberSource.next({
"items": res.body,
"totalPages": parseInt(res.headers.get('x-paging-pagecount'))
}))
).subscribe();
}
}
我可以看到网络调用是正确的,但是页面上没有显示结果。
我建议你重构 replayVenueApi
如下:
replayVenueApi(page, name) {
this.httpService.getVenuesListViaPost(`?pageno=${page}&pageSize=10`, { name }).pipe(
tap(res => this._rememberSource.next({
"items": res.body,
"totalPages": parseInt(res.headers.get('x-paging-pagecount'))
}))
).subscribe();
}
这不会实现您的“如果少于 20 秒就不要重复请求”,但这确实意味着您的 ReplaySubject 将发出。
在您的组件中,您需要使用 Observable,因为 replayVenuApi
没有 return 任何东西:
getData(page: number) {
this.listedAsyncData$ = this.replayApiService.remember$;
this.replayApiService.replayVenueApi(page, this.name);
}
对于计时器元素,一种可能的方法是存储时间戳并将其与每次调用 replayVenueApi()
的 Date.now()
进行比较。如果差异小于 20 秒,则您什么都不做。如果更多,你提出要求。