簡體   English   中英

如何只訂閱一次可觀察的

[英]How to subscribe observable only once

我正在嘗試訂閱兩個 observable 並將值存儲在數組 object 中。 它工作正常,但我的問題是它重復了三次,我不明白。 我在一項服務中這樣做是為了創建一項新服務。 下面是代碼示例。 我也想知道我可以使用 promise 而不是在 angular 中觀察到嗎? 或者我可以將 observable 轉換為 promise 並在獲得值后解決? 謝謝您的幫助

 addEmployeeData() {
    const employeeObservable = this.apiService.getEmployeeDataObservable();
    employeeObservable.subscribe({
      next: (res: any) => {
        let employee = res;
        const paramsObservable = this.apiService.getParamsObservable();
        pageParamsObservable.subscribe({
          next: (pageParams: any) => {

是的,你可以像使用 Promises 一樣使用 Observables:

async asyncAddEmployeeData(): Promise<any> {
  return this.apiService.getEmployeeDataObservable()
    .pipe(
      mergeMap(employeeData => this.apiService.getParamsObservable()
        .pipe(
          tap((paramsData): void => {
            // There is available data
            // from apiService.getEmployeeDataObservable()
            // as employeeData variable
            // and data from apiService.getParamsObservable()
            // as paramsData.
            // You can do in tap function all the same
            // as in next in the subscribe.
          }),
        )
      ),
    )
    .toPromise();
}

並像這里一樣使用它:

async ngOnInit(): Promise<void> {
  // ngOnInit just for example.
  const someVariable = await this.asyncAddEmployeeData();
}

但是使用 Observable 的常規方式如下所示:

addEmployeeData(): Observable<any> {
  return this.apiService.getEmployeeDataObservable()
    .pipe(
      mergeMap(employeeData => this.apiService.getParamsObservable()
        .pipe(
          tap(paramsData => {
            // There is available data
            // from apiService.getEmployeeDataObservable()
            // as employeeData variable
            // and data from apiService.getParamsObservable()
            // as paramsData.
          }),
        )
      ),
      take(1), // Just if you need only first value, if not, please, remove this string.
    );
}

和訂閱:

ngOnInit(): void {
  // ngOnInit just for example.
  this.subscription = this.addEmployeeData().subscribe();
}

不要忘記取消訂閱以避免 memory 泄漏:

ngOnDestroy(): void {
  this.subscription.unsubscribe();
}

由於您有 2 個 Observables 並且您僅在訂閱第二個 observable 之后才執行實際邏輯,我假設沒有第二個 observable 數據,您沒有實現任何邏輯。

為此,您有 go 的 2 個選項。

  1. 使用 mergeMap RxJS 運算符並按照 Mikhail Filchushkin 上面所說的進行操作。

(或者)

  1. 我的方法是使用combineLatest運算符,並在訂閱完成后使用 Subject 變量銷毀訂閱。 這是你如何做到這一點:

mergeMap相比,此方法的優點是您將只有一個訂閱和一個取消訂閱,而在mergeMap中您將有 2 個。

MergeMap 將訂閱第一個變量,如果它成功訂閱,那么只有它會訂閱第二個訂閱。

combineLatest中,無論即將到來的數據如何,它都會訂閱。

根據您的使用方式,這是一種優勢和劣勢。

如果您只想要第一個值,請使用take(1)運算符阻止它進一步訂閱

const employeeObservable = this.apiService.getEmployeeDataObservable();
const paramsObservable = this.apiService.getParamsObservable();

destroy$: Subject<any> = new Subject(); // This is used to destroy the subscription later

// Combine the observables and destroy once done in 1 shot.

combineLatest(employeeObservable,paramsObservable)
  .pipe(
      takeUntil(this.destroy$),
      take(1)
   )
  .subscribe(
     ([employeeObservableData, paramsObservableData]) => {
        if (employeeObservableData && paramsObservableData) {
          // do your logic here
        }  
     }
  );

ngOnDestroy() {
   this.destroy$.next();
   this.destroy$.complete();
}

  1. 您可以使用任何 RxJS 高階映射運算符(如switchMap )從一個可觀察對象切換到另一個相互依賴的可觀察對象。
addEmployeeData() {
  this.apiService.getEmployeeDataObservable().pipe(
    switchMap(_ => {
      let employee = res;  // why is this needed though?
      return this.apiService.getParamsObservable();
    })
  ).subscribe({
    next: (pageParams: any) => { 
      // handle response
    },
    error: (error: any) => {
      // handle error
    }
  );
}
  1. 如果 observables 彼此不相關(例如,如果第二個請求不依賴於第一個請求的結果),您可以使用 RxJS forkJoincombineLatest等函數來並行觸發 observables。

    有關映射運算符和組合函數快速比較,請參閱我的帖子。

  2. 最好關閉ngOnDestroy中的任何開放訂閱,這樣它們就不會持續存在並導致潛在的 memory 泄漏。 有多種方法可以關閉訂閱。

    3.1 unsubscribe - 將訂閱分配給一個成員變量並在ngOnDestroy鈎子中調用unsubscribe()

    3.2 take(1) - 在發出第一個通知后關閉訂閱。

    3.3 first() - 與take(1)類似,但如果沒有任何發射與謂詞匹配,則采用額外的謂詞並發出錯誤。 請參閱此處了解take(1)first()

    3.4. takeUntil() - 使用額外的多播以單次發射關閉多個打開的訂閱。 最喜歡的方式是它的優雅。 請參閱此處了解更多信息。

注意:Angular HttpClient 返回的 Observables 在第一次發射后完成,無需任何上述操作。 所以在大多數情況下,它們不是必需的。

嘗試在 onDestroy 上創建訂閱並取消訂閱。

// import 
import { Subscription } from 'rxjs';

subscription: Subscription;

ngOnInit() { 
    this.subscription = // employeeObservable.subscribe()
}

ngOnDestroy() { 
    this.subscription.unsubscribe();
}

暫無
暫無

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

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