[英]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
}
Now thing is that I have to use this valueMap
in the method buidlContainer()
, hence I need to get the complete map first from service.现在的事情是我必须在方法
buidlContainer()
中使用这个valueMap
,因此我需要首先从服务中获取完整的 map。 And when I use that map in buildConatainer() it shows me undefined.当我在 buildConatainer() 中使用 map 时,它显示我未定义。
I understood that this is some async call issue.我知道这是一些异步调用问题。 Also, I can not call method buildContainer() for each value in.subscribe() as that would not be better idea.
此外,我不能为 in.subscribe() 中的每个值调用方法 buildContainer(),因为这不是更好的主意。 So, I have to compute the Map first before processing that further..
所以,在进一步处理之前,我必须先计算 Map。
Any help is appreciated and i can not modify the service from returning Observable to return Promise感谢您提供任何帮助,我无法将服务从返回 Observable 修改为返回 Promise
i want to do as below我想做如下
private buildContainer(): void {
for([key,data] of this.valueMap) {
-----some code----
}
}
Simply use forkJoin
to wait for all observables to finish.只需使用
forkJoin
等待所有可观察对象完成。 forkJoin
will bundle all observables into one. forkJoin
将把所有的 observable 打包成一个。 This observable can be returned and inside ngOnInit
you subscribe to it and call buildContainer
.这个 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);
}
The code would be even cleaner if you do not populate the valueMap
inside the tap
operator and instead use the result you get into your subscription function.如果您不在
tap
运算符中填充valueMap
,而是使用您在订阅 function 中获得的结果,代码会更加简洁。
This is one of the disadvantage (or advantage depending how you look at it) of introducing reactive paradigm to your code.这是将响应式范式引入代码的缺点之一(或优点取决于您如何看待它)。 A single point of reactive procedure would gradually creep into other parts of the code either partially or completely.
反应过程的单点会逐渐部分或完全潜入代码的其他部分。
So I'd recommend you to make the valueMap
reactive as well and make it respond based on the changes in getDataFromService()
service.因此,我建议您也使
valueMap
具有响应性,并使其根据getDataFromService()
服务中的更改进行响应。 One way would to make the valueMap
variable a RxJS ReplaySubject
with a buffer of 1. So it'll buffer (or hold) it's last value pushed to it and emit it immediately upon subscription.一种方法是将
valueMap
变量设置为 RxJS ReplaySubject
,缓冲区为 1。因此它将缓冲(或保持)它的最后一个值,并在订阅时立即发出它。
Try the following尝试以下
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();
}
I've also used RxJS forkJoin()
function to combine multiple observables and takeUntil
operator close the subscription when the component is destroyed.我还使用 RxJS
forkJoin()
function 来组合多个可观察对象,并在组件被销毁时使用takeUntil
运算符关闭订阅。
Working example: Stackblitz工作示例: Stackblitz
In the example, I've used jsonplaceholder
API to mock some HTTP calls in the fetchService()
function.在示例中,我使用
jsonplaceholder
API 来模拟fetchService()
function 中的一些 HTTP 调用。
Note:笔记:
The forkJoin()
will emit only if all the observables complete.仅当所有可观察对象都完成时,
forkJoin()
才会发出。 If you're dealing with a stream of data, you will have to replace it with either combineLatest
or zip
based on your requirement.如果您正在处理 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 数据,则必须根据您的要求将其替换为
combineLatest
或zip
。
There is an obvious issue where if the buildContainer()
function is called multiple times in quick successions, each will trigger individual subscriptions.有一个明显的问题,如果
buildContainer()
function 被快速连续调用多次,每个都会触发单独的订阅。
Remove buildContainer from ngOnInit and Call the method inside the subscribe从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.