[英]Angular Observable need to complete first
@Input() list: string[];
ngOnInit() : void {
this.valueMap = new Map<any, any>();
this.getDataFromService();
this.buildContainer();
}
private getDataFromService(): void {
this.list.forEach(value-> {
this.fetchService(value).subscribe(data ->{
this.valueMap.set(value,data);
}
)
})
}
private buildContainer(): void {
console.log(this.valueMap.size); // shows always 0 even when service returns the data
}
現在的事情是我必須在方法buidlContainer()
中使用這個valueMap
,因此我需要首先從服務中獲取完整的 map。 當我在 buildConatainer() 中使用 map 時,它顯示我未定義。
我知道這是一些異步調用問題。 此外,我不能為 in.subscribe() 中的每個值調用方法 buildContainer(),因為這不是更好的主意。 所以,在進一步處理之前,我必須先計算 Map。
感謝您提供任何幫助,我無法將服務從返回 Observable 修改為返回 Promise
我想做如下
private buildContainer(): void {
for([key,data] of this.valueMap) {
-----some code----
}
}
只需使用forkJoin
等待所有可觀察對象完成。 forkJoin
將把所有的 observable 打包成一個。 這個 observable 可以返回並在ngOnInit
訂閱它並調用buildContainer
。
@Input() list: string[];
ngOnInit(): void {
this.valueMap = new Map<any, any>();
this.getDataFromService().subscribe(_ => this.buildContainer());
}
private getDataFromService(): Observable<any> {
return forkJoin(
this.list.map(value =>
this.fetchService(value).pipe(
tap(data => this.valueMap.set(value, data))
)
)
);
}
private buildContainer(): void {
console.log(this.valueMap.size);
}
如果您不在tap
運算符中填充valueMap
,而是使用您在訂閱 function 中獲得的結果,代碼會更加簡潔。
這是將響應式范式引入代碼的缺點之一(或優點取決於您如何看待它)。 反應過程的單點會逐漸部分或完全潛入代碼的其他部分。
因此,我建議您也使valueMap
具有響應性,並使其根據getDataFromService()
服務中的更改進行響應。 一種方法是將valueMap
變量設置為 RxJS ReplaySubject
,緩沖區為 1。因此它將緩沖(或保持)它的最后一個值,並在訂閱時立即發出它。
嘗試以下
import { forkJoin, ReplaySubject, Subject } from 'rxjs';
import { take, takeUntil } from 'rxjs/operators';
valueMap: ReplaySubject<Map<any, any>> = ReplaySubject<Map<any, any>>(1);
completed$ = new Subject<any>();
@Input() list: string[];
ngOnInit(): void {
this.valueMap = new Map <any, any>();
this.getDataFromService();
this.buildContainer();
}
private getDataFromService(): void {
forkJoin(this.list.map(value => this.fetchService(value))).pipe(
takeUntil(this.completed$) // <-- close subscription upon component `ngOnDestroy` hook trigger
).subscribe(
data => {
let map = new Map<any, any>();
data.forEach((item, i) => {
map.set(this.list[i], item);
});
this.valueMap.next(map);
}
);
}
private buildContainer(): void {
this.valueMap.asObservable().pipe(
take(1) // <-- emit only the first notification and complete
).subscribe(
data => {
console.log(this.valueMap.size);
}
);
}
ngOnDestroy() {
this.completed$.next();
this.completed$.complete();
}
我還使用 RxJS forkJoin()
function 來組合多個可觀察對象,並在組件被銷毀時使用takeUntil
運算符關閉訂閱。
工作示例: Stackblitz
在示例中,我使用jsonplaceholder
API 來模擬fetchService()
function 中的一些 HTTP 調用。
筆記:
僅當所有可觀察對象都完成時, forkJoin()
才會發出。 如果您正在處理 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 數據,則必須根據您的要求將其替換為combineLatest
或zip
。
有一個明顯的問題,如果buildContainer()
function 被快速連續調用多次,每個都會觸發單獨的訂閱。
從ngOnInit 中刪除 buildContainer並調用subscribe中的方法
private getDataFromService(): void {
this.list.forEach((value, index) -> {
this.fetchService(value).subscribe(data ->{
this.valueMap.set(value,data);
}
)
if(this.list.length-1 == index){
this.buildContainer(); // call here
}
})
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.