Angular 等待所有订阅

Angular 等待所有订阅,angular,promise,Angular,Promise,我有一个组件,当前设置如下: export class CompareComponent implements OnInit, OnDestroy { criteria: Criteria[] products: Product[] = []; private organisationId: string private criteriaSubscription: Subscription private routeSubscription: Subscription

我有一个组件,当前设置如下:

export class CompareComponent implements OnInit, OnDestroy {
  criteria: Criteria[]
  products: Product[] = [];

  private organisationId: string

  private criteriaSubscription: Subscription
  private routeSubscription: Subscription
  private productSubscription: Subscription

  constructor(
    @Inject(PLATFORM_ID) private platformId: Object,
    private route: ActivatedRoute,

    private attributeMatchService: AttributeMatchService,
    private criteriaService: CriteriaService,
    private optionsService: OptionsService,
    private productService: ProductService,
  ) { }

  ngOnInit() {
    this.organisationId = this.optionsService.get().organisation;
    this.routeSubscription = this.route.paramMap.subscribe(paramMap => {
      let category = paramMap.get('category');
      let gtins = paramMap.get('gtins').split('.');
      this.listCriteria(category);
      this.listProducts(category, gtins);
    });
  }

  ngOnDestroy() {
    if (this.criteriaSubscription) this.criteriaSubscription.unsubscribe();
    if (this.productSubscription) this.productSubscription.unsubscribe();
    if (this.routeSubscription) this.routeSubscription.unsubscribe();
  }

  close() {
    if (isPlatformServer(this.platformId)) return;
    window.history.back();
  }

  private listCriteria(category: string): void {
    this.criteriaSubscription = this.criteriaService.list(category, 'Attributes').subscribe(criteria => this.criteria = criteria);
  }

  private listProducts(category: string, gtins: string[]) {
    gtins.forEach(gtin => {
      this.productSubscription = this.productService.get(category, this.organisationId, parseInt(gtin)).subscribe(products => {
        this.products.push(products[0]);
      });
    });
  }
}
listProducts
方法中可以看到,我得到了一个基于gtins的产品列表,这些产品已作为参数传递。 我想做的是等待所有订阅在
listProducts
中完成,然后运行一些代码


我该怎么做?

我相信您需要使用
forkJoin

它等待阵列中的所有可观测数据完成,然后发射

在每个可观察操作中执行
轻触

private listProducts(category: string, gtins: string[]) {
    const products$: Observable<any>[] = [];

    gtins.forEach(gtin => {
        products$.push(this.productService.get(category, 1, parseInt(gtin))
                        .pipe(tap(product => {
                              this.products.push(products[0]);
        }));
    });

    forkJoin(products$).subscribe(() => {
        console.log('All subscriptions done');
    });
}
私有列表产品(类别:string,gtins:string[]){
const products$:可观察[]=[];
gtins.forEach(gtin=>{
products$.push(this.productService.get(category,1,parseInt(gtin))
.管道(水龙头)(产品=>{
这个.products.push(products[0]);
}));
});
forkJoin(产品$)。订阅(()=>{
log(“完成所有订阅”);
});
}

我相信您需要使用
forkJoin

它等待阵列中的所有可观测数据完成,然后发射

在每个可观察操作中执行
轻触

private listProducts(category: string, gtins: string[]) {
    const products$: Observable<any>[] = [];

    gtins.forEach(gtin => {
        products$.push(this.productService.get(category, 1, parseInt(gtin))
                        .pipe(tap(product => {
                              this.products.push(products[0]);
        }));
    });

    forkJoin(products$).subscribe(() => {
        console.log('All subscriptions done');
    });
}
私有列表产品(类别:string,gtins:string[]){
const products$:可观察[]=[];
gtins.forEach(gtin=>{
products$.push(this.productService.get(category,1,parseInt(gtin))
.管道(水龙头)(产品=>{
这个.products.push(products[0]);
}));
});
forkJoin(产品$)。订阅(()=>{
log(“完成所有订阅”);
});
}

如果要等待所有可观察到的结果,请使用
forkJoin
操作符,然后将结果展平,将其推送到产品阵列中

我还建议使用
takeUntil
操作符作为订阅的清理助手。请参见我的示例中如何使用它

forkJoin(
      gtins.forEach(gtin => this.productService.get(category, this.organisationId, parseInt(gtin)))
    ).pipe(
      takeUntil(this.destroyed$)
    ).subscribe(products => {
      this.products.push(...products.flat())
    });
在你的
onDestroy
hook中

  onDestroy() {
    this.destroyed$.next();
    this.destroyed$.complete();
  }
在组件中,将
销毁的$
定义为


destrocted$:Subject=new Subject();

如果要等待所有观察值,请使用
forkJoin
操作符,然后展平结果以将其推送到产品数组中

我还建议使用
takeUntil
操作符作为订阅的清理助手。请参见我的示例中如何使用它

forkJoin(
      gtins.forEach(gtin => this.productService.get(category, this.organisationId, parseInt(gtin)))
    ).pipe(
      takeUntil(this.destroyed$)
    ).subscribe(products => {
      this.products.push(...products.flat())
    });
在你的
onDestroy
hook中

  onDestroy() {
    this.destroyed$.next();
    this.destroyed$.complete();
  }
在组件中,将
销毁的$
定义为


destrocted$:Subject=新主题()

我想你是在寻找类似这样的东西来组合可观察对象并等待所有人,这是RxJs你可能还想查看我想你是在寻找类似这样的东西来组合可观察对象并等待所有人,这是RxJs你可能还想查看@ritaj击败我,但我将此作为参考对于一个链接式的答案。推入
subscribe
而不是
map
,不是更为惯用吗?(AFAIK
map
在函数式反应式编程中应该没有副作用)@meriton,非常正确,因为我们不变异数据,所以不需要映射!谢谢!)@meriton是的,它应该在
点击
订阅
@DanielB内部完成,不仅如此,您还可以将结果映射到
此.products
数组的长度(因为推送返回数组长度),这将为以后的流链接丢失信息。@ritaj抢先告诉了我,但我将把它作为链接答案的参考。推入
subscribe
而不是
map
?(在函数式反应式编程中,AFAIK
map
应该是没有副作用的)@meriton,非常正确,因为我们不变异数据,所以不需要映射!谢谢!:)@meriton是的,应该在
点击
订阅
@DanielB内完成,不仅如此,您还可以将结果映射到
this.products
数组的长度(因为推送返回数组长度),这将为以后的流链接丢失信息。