[英]RXJS How to Know When Finalize Completes?
我對 RXJS 比較陌生,所以如果重復,我深表歉意。 我嘗試搜索答案,但找不到任何答案,可能是因為我不知道要使用哪些搜索詞。
我試圖了解如何知道服務調用的 finalize 塊何時完成,因為它更新了共享的 state 變量。
這是它的堆棧閃電戰,盡管我也會在下面發布片段: https://stackblitz.com/edit/angular-ivy-xzvkjl
我有一個 Angular 應用程序,其服務將共享isLoading
標志設置為 true,啟動 HTTP 請求,然后使用finalize
將isLoading
標志設置回 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 塊的完整處理程序之后調用serviceCall
的finalize
? 如果不是通過已完成的處理程序,我應該如何知道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.