簡體   English   中英

RXJS 如何知道 Finalize 何時完成?

[英]RXJS How to Know When Finalize Completes?

我對 RXJS 比較陌生,所以如果重復,我深表歉意。 我嘗試搜索答案,但找不到任何答案,可能是因為我不知道要使用哪些搜索詞。

我試圖了解如何知道服務調用的 finalize 塊何時完成,因為它更新了共享的 state 變量。

這是它的堆棧閃電戰,盡管我也會在下面發布片段: https://stackblitz.com/edit/angular-ivy-xzvkjl

我有一個 Angular 應用程序,其服務將共享isLoading標志設置為 true,啟動 HTTP 請求,然后使用finalizeisLoading標志設置回 false,這樣無論成功還是錯誤,檢查isLoading標志的項目知道 HTTP 請求不再處理。

我已經將該場景簡化為單獨的方法而不是單獨的類:

isLoading = false;

public ngOnInit() {
  this.serviceCall().subscribe(
    next => {
      console.log("value of isLoading in next handler: " + this.isLoading);
    },
    err => {
      console.log("value of isLoading in error handler: " + this.isLoading);
    },
    () => {
      console.log("value of isLoading in complete handler: " + this.isLoading);
    }
  );
}

private serviceCall() {
  this.isLoading = true;
  return this.httpCall().pipe(
    tap(value => console.log(value)),
    finalize(() => {
      this.isLoading = false;
      console.log("Value of isLoading in serviceCall finalize: " + this.isLoading);
    })
  );
}

private httpCall() {
  return new Observable(subscriber => {
    console.log("Starting emissions");
    subscriber.next(42);
    subscriber.next(100);
    subscriber.next(200);
    console.log("Completing emissions");
    subscriber.complete();
  });
}

我驚訝地發現這個例子的 output 是

開始排放

42

下一個處理程序中 isLoading 的值:true

100

下一個處理程序中 isLoading 的值:true

200

下一個處理程序中 isLoading 的值:true

完成排放

完整處理程序中 isLoading 的值:true

serviceCall finalize 中 isLoading 的值:false

為什么在ngOnInit的 subscribe 塊的完整處理程序之后調用serviceCallfinalize 如果不是通過已完成的處理程序,我應該如何知道serviceCall何時完成了對共享變量的操作?

關於finalize

這歸結為finalize是如何實現的。 我同意這可能不是很直觀。 我是一個分裂派系的一部分,我相信它現在的實施方式直觀的方式。

考慮一個在發出任何東西之前取消訂閱的 observable。 我希望 finalize 仍會觸發,但我不希望將complete的通知發送給我的觀察者。

六個一個,六個另一個

通常,發生在 stream 上的最后一件事是取消訂閱。 當取消訂閱 stream 時,將調用 Finalize。 這發生在完成或錯誤發射之后。

您可以將 finalize 視為在可觀察對象的拆卸過程中發生的事情。 而觀察者正在觀察仍然存在的可觀察對象的發射。


盡可能避免副作用

一般來說,設置全局變量和稍后在同一pipeline中檢查它們等副作用被認為是代碼異味。 相反,如果您更加努力地采用 RxJS 流所倡導的功能方法,則此類問題應該會消失。


快速旁白:

定時異步事件通常會導致奇怪或意外的結果(如果你能提供幫助,你真的不應該手動實現這種事情的部分原因)。

考慮一下當我在您的 stream 中添加延遲時會發生什么:

private serviceCall() {
  this.isLoading = true;
  return this.httpCall().pipe(
    tap(value => console.log(value)),
    finalize(() => {
      this.isLoading = false;
      console.log("Value of isLoading in serviceCall finalize: " + this.isLoading);
    }),
    delay(0)
  );
}

你會認為 0 毫秒的延遲應該沒有什么區別,但是因為每個延遲都會放在 JS 的微任務隊列中,你會注意到代碼運行方式的顯着差異。 在使用第一個值調用您的 subscribe 之前, isLoading已經為 false。

那是因為延遲之前的一切都是同步運行的,並且會在微任務隊列運行之前完成。 delay(0)之后的一切都是異步運行的,並且會在下次 JS 准備好運行微任務隊列時完成。


最小阻力的解決方案

這不是慣用的 RxJS,但它會按照您期望 finalize 在這種情況下的工作方式工作。

您可以使用點擊運算符來捕獲complete的發射。 由於 tap 將觸發complete ,這應該在subscribe之前觸發,因此適用於您的用例。

function serviceCall() {
  const setIsLoading = bool => (_ = null) => this.isLoading = bool;
  
  return defer(() => {
    setIsLoading(true)();
    return this.httpCall().pipe(
      tap({
        next: console.log,
        error: setIsLoading(false),
        complete: setIsLoading(false)
      })
    );
  });

}

暫無
暫無

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

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