簡體   English   中英

Angular 5,rxjs-僅在運行另一個進程之前等待可觀察對象完成

[英]Angular 5, rxjs- wait for observable to finish only if it is in a middle of a run before running another process

我的主要組件中有一個 3 秒的計時器。 在計時器內我執行 http 調用-

    constructor(){
          this.timer = timer(3000, 3000);
          this.timerObservable = this.timer.subscribe(x => {
              this.http.get(URL).subscribe(()=>{
              //DO SOMETHING
              });
          });

     }

在另一個組件中,我有一個按鈕,假設執行不同的 http 調用,按下按鈕調用 sumbit 函數 -

        submit(){
            this.http.get("/sumbitForm").subscribe(()=> {
              //DO SOMETHING
             })
         }

當用戶單擊按鈕時,如果計時器正在處理中(其中的 http 被調用但尚未解析),我想在對按鈕執行 http 調用之前等待,直到它解析為止,但如果計時器沒有在處理中(上次調用的時間尚未過去)我想立即執行它。

我認為 forkJoin 和 concat 在這里不相關(這是一個計時器,而不是我想以任何方式等待執行的“常規”訂閱)並且我找不到一個很好的方法來做到這一點,知道嗎?

您需要在兩個組件之間共享一些信息,即輪詢請求何時在進行中,何時不在。 您應該為此使用服務。 將您的 http 請求邏輯移動到服務而不是直接在組件中使用 HttpClient 也是一種很好的做法。 這允許您在一個地方進行一般錯誤處理。 我們將此服務稱為 ApiService。

服務

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject, interval } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class ApiService {
  // Use a BehaviorSubject to notify listeners about ongoing polling requests.
  // A BahaviorSubject always has a current value that late subscribers will 
  // receive immediately upon subscribing
  private pollRequestInProgress = new BehaviorSubject<boolean>(false);
  // Share this BehaviorSubject as an Observable
  public pollRequestInProgress$ = pollRequestInProgress.asObservable();

  constructor(private http: HttpClient)

  doPoll(url: string): Observable<any> {
    return interval(3000).pipe( // interval(3000) is equivalent to timer(3000, 3000)
      tap(_ => pollRequestInProgress.next(true)), // notify that a poll request is about to happen
      switchMap(_ => this.http.get(url)), // do your poll request
      tap(_ => pollRequestInProgress.next(false)) // notify that your poll request ended
    );
  }
}

主組件

這是您要從中開始輪詢的組件。

private destroy$: Subject<void> = new Subject<void>();

constructor(private apiService: ApiService) {}

// move logic to ngOnInit instead of constructor
ngOnInit() {
  // subscribe and thereby start the polling
  this.apiService.doPoll(URL).pipe(takeUntil(this.destroy$))
    .subscribe(pollResponse => {
      //DO SOMETHING
    });
}

ngOnDestroy() {
  // unsubscribe when the Component gets destroyed.
  this.destroy$.next();
  this.destroy$.complete();
}

特征組件

這是當您單擊按鈕時要在其中執行 http 請求的組件。

constructor(private http: HttpClient, private apiService: apiService) {}

submit() {
  // Listen to whether a polling request is currently in progress.
  // We will immediately receive a value upon subscribing here, because we used 
  // a BehaviorSubject as the underlying source.
  this.apiService.pollRequestInProgress$.pipe(
    // Emit the first item that tells you that no polling request is in progress.
    // i.e. let the first 'requestInProgress === false' through but not any 
    // other items before or after.
    first(requestInProgress => !requestInProgress),
    // If no polling request is in progress, switch to the http request you want 
    // to perform
    switchMap(this.http.get("/sumbitForm")) // <-- consider moving this http.get to your ApiService aswell
  ).subscribe(httpResponse => {
    // you've got your http response here
  });
  // you don't have to unsubscribe here as first and http.get both complete 
  // and thus unsubscribe automatically
}

在此處查看上面代碼邏輯的簡單示例: https : //stackblitz.com/edit/rxjs-t4hjcr

您可以使用角度主題

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class CallService {
    private subject = new Subject<any>();

    timerCompleted() {
        this.subject.next();
    }

    checkTimer(): Observable<any> {
        return this.subject.asObservable();
    }
}

應用程序組件使用調用服務訂閱計時器完成並使它們可用於應用程序組件模板。

import { Component, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';

import { CallService } from './_services/index';

@Component({
    selector: 'app',
    templateUrl: 'app.component.html'
})

export class AppComponent implements OnDestroy {

    subscription: Subscription;

    constructor(private callService: CallService) {

        this.subscription = this.callService.checkTimer().subscribe(() => { 
           // call your api after timer complete
        });
    }

    ngOnDestroy() {
        // unsubscribe to ensure no memory leaks
        this.subscription.unsubscribe();
    }
}

在您的計時器中添加以下代碼

this.timer = timer(3000, 3000);
        this.timerObservable = this.timer.subscribe(x => {
           this.http.get(URL).subscribe(()=>{
               this.callService.timerCompleted();
           });
        });

如需更多參考,您可以查看http://jasonwatmore.com/post/2018/06/25/angular-6-communicating-between-components-with-observable-subject

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM