Angular 角度-订阅多次而不触发多次调用?

Angular 角度-订阅多次而不触发多次调用?,angular,rxjs,Angular,Rxjs,我有一个服务调用,其响应缓存在我的Angular服务中,如下所示: public cacheMyServiceResponse(): Observable<any> { return this.appConfig.getEndpoint('myService') .pipe( switchMap((endpoint: Endpoint) => this.http.get(endpoint.toUrl())), tap((body: any)

我有一个服务调用,其响应缓存在我的Angular服务中,如下所示:

public cacheMyServiceResponse(): Observable<any> {
  return this.appConfig.getEndpoint('myService')
    .pipe(
      switchMap((endpoint: Endpoint) => this.http.get(endpoint.toUrl())),
      tap((body: any) => {
        if (body) { //  this endpoint can also return a 204 (No Content), where body is null
          this.cache = body.myData;
        }
      }),
      take(1),
      catchError(error => {
        this.errorService.trackError(error.status);
        return of(true);
      })
    );
}
ngOnInit() {
    this.myService.cacheMyServiceResponse().subscribe();
}
但是在其他地方,我需要知道它是否已经完成了调用,而不需要触发我的http调用两次

onClick() {
    this.myService.cacheMyServiceResponse().subscribe(() => {
       // call is finished..
    });
}
目前,该服务将被调用两次。我该怎么做


PS:我没有故意进行错误处理,我只需要知道服务调用是否完成。

使用布尔变量检查实际响应的状态,或者我们的调用是否完成(成功或错误);然后,当用户单击按钮时,可以检查此布尔值。。。下面的代码解释我的意思

  callMade:boolean = false;
  callFinished:boolean = false;

  ngOnInit(){
    this.callMade = true;
    this.myService.cacheMyServiceResponse().subscribe(
          dataa => { /* get and process data */}
          ,() => { /*this is the finally block */
          this.callFinished = true;
          }
    );
  }

  someOtherFunction(){
    if (this.callMade == true && this.callFinished == false){
      /* call the service again */
    }
  }

您可以在此处为您的场景使用
解析器。当你点击你的路线时,它会调用你的方法

例如:

@Injectable()
export class ExampleResolver implements Resolve<any> {
  constructor(private apiService: APIService) {}

  resolve(route: ActivatedRouteSnapshot) {
    return this.apiService.getItems(route.params.date);
  }
}

你为什么不保存可观察的

public cacheMyServiceResponse(): Observable<any> {
  if(this.cache) {
      return of(this.cache);
  else if(!this.currentCall) {
    this.currentCall = this.appConfig.getEndpoint('myService')
      .pipe(
        switchMap((endpoint: Endpoint) => this.http.get(endpoint.toUrl())),
        tap((body: any) => {
          if (body) { //  this endpoint can also return a 204 (No Content), where body is null
            this.cache = body.myData;
          }
        }),
        take(1),
        catchError(error => {
          this.errorService.trackError(error.status);
          return of(true);
        })
      );
  }
  return this.currentCall;
}
public cacheMyServiceResponse():可观察{
if(this.cache){
返回(this.cache);
如果(!this.currentCall){
this.currentCall=this.appConfig.getEndpoint('myService'))
.烟斗(
switchMap((endpoint:endpoint)=>this.http.get(endpoint.toUrl()),
点击((主体:任意)=>{
if(body){//此端点还可以返回204(无内容),其中body为null
this.cache=body.myData;
}
}),
以(1)为例,
catchError(错误=>{
this.errorService.trackError(error.status);
返回(真);
})
);
}
返回此.currentCall;
}
我建议使用并订阅
ReplaySubject()
onClick,它将等待您的服务发出数据,而它仍然可以订阅,如果在服务发出数据之前没有订阅,您也不会错过数据:

yourWaitingData = new ReplaySubject();
subscription;

ngOnInit() {
    this.myService.cacheMyServiceResponse().subscribe(res => {
        //yourWaitingData only emit when res is return from API call
        this.yourWaitingData.next(res)
    });
}
然后订阅:

onClick() {
    if(this.subscription){
       this.subscription.unsubscribe()
    }
    this.subscription = this.yourWaitingData.subscribe((x) => {
       // subscribed and will wait for data to be emited from service
       console.log(x)
    });
}

使用
shareReplay
创建一个简单的缓存,该缓存触发http请求一次,并将其返回值提供给缓存中的所有后续订阅

服务


private cache$:Observable

首先,在我的示例中,页面加载后也可以调用该按钮,我想在那里等待,比如说最长10秒。因此,我实际上不能只检查一个变量。其次,我问这个问题,希望这可以通过纯rxjs实现。@akcasoy你没有问过最后一部分特别清楚。对不起。但是一旦你接到服务电话,你总是要处理那些还没有回复的情况。在我的问题中,我使用了“.订阅(()”在onClick回调函数中。我想它清楚地表明了我想等待响应,您可以在这里为您的场景使用
解析器
。当您点击路由时,它将调用您的方法。示例:
@Injectable()导出类APIResolver实现Resolve{constructor(私有apiService:apiService){解析(route:ActivatedRouteSnapshot){返回this.apiService.getItems(route.params.date);}}
{path:'items/:date',component:ItemsComponent,解析:{items:apisresolver}}
它将在您的ngOnInit()之前得到您的响应。此外,您还可以将响应存储在服务缓存中。可能行为主体会更好,否则您可能会错过response@Random感谢您指出,使用
ReplaySubject
onClick() {
    if(this.subscription){
       this.subscription.unsubscribe()
    }
    this.subscription = this.yourWaitingData.subscribe((x) => {
       // subscribed and will wait for data to be emited from service
       console.log(x)
    });
}