[英]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.