[英]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 個選項。
(或者)
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();
}
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
}
);
}
如果 observables 彼此不相關(例如,如果第二個請求不依賴於第一個請求的結果),您可以使用 RxJS forkJoin
或combineLatest
等函數來並行觸發 observables。
有關映射運算符和組合函數的快速比較,請參閱我的帖子。
最好關閉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.