【问题标题】:Remove for loop from observable subscribe从可观察订阅中删除 for 循环
【发布时间】:2023-03-28 11:00:01
【问题描述】:
this.httpService
          .getCustomer(id)
          .pipe(
            switchMap((customerObj) => this.httpService.getCustomerAccount(customerObj.account_id)),
            switchMap((accountObj) =>
              this.httpService.getAccountHoliday(accountObj.holiday_id),
            ),
          )
          .subscribe((holidays: Holiday[]) => {
            for (const holiday of holidays) {
              this.httpService.getDestination(holiday.dest_id).subscribe((destination) => {
                if (holiday.identifier === destination.name) {
                  console.log(holiday);
                }
              });
            }
          });

我想做这样的事情

  this.httpService
      .getCustomer(id)
      .pipe(
        switchMap((customerObj) => this.httpService.getCustomerAccount(customerObj.account_id)),
        switchMap((accountObj) =>
          this.httpService.getAccountHoliday(accountObj.holiday_id),
        ),
        filter(holiday => this.httpService.getDestination(holiday.dest_id).name === holiday.identifier)
      )
      .subscribe((holiday: Holiday[]) => {
        for (const holiday of holidays) {
          console.log(holiday);
        }
      });

也就是说,将 for 循环的逻辑与过度服务合并,即我需要在订阅之前过滤掉假期。我该怎么做?

【问题讨论】:

  • 您介意解释清楚用例吗?

标签: angular rxjs rxjs-observables


【解决方案1】:

这样的?您可以在 switchMap 中合并循环调用。

由于我没有您的代码,因此不确定这是否可以完美编译,但类似的东西应该可以解决问题。

this.httpService.getCustomer(id).pipe(
  
  switchMap(customerObj => 
    this.httpService.getCustomerAccount(customerObj.account_id)
  ),

  switchMap(accountObj =>
    this.httpService.getAccountHoliday(accountObj.holiday_id),
  ),

  map((holidays: Holiday[]) => holidays.map(holiday => 
    this.httpService.getDestination(holiday.dest_id).pipe(
      filter(destination => holiday.identifier === destination.name),
      mapTo(holiday)
    )
  )),

  switchMap(filteredHolidays => merge(...filteredHolidays)),

).subscribe(console.log);

你也可以用 forkJoin 代替 merge 来一次性得到一个数组。这里棘手的一点是 forkJoin 不知道如何处理一个完成但不发射的 observable,所以我们不能过滤直到 forkJoin 之后。在这种情况下,解决方法是将我们不感兴趣的响应映射到 null,然后过滤 null 之后的值。

可能看起来像这样:

this.httpService.getCustomer(id).pipe(

  switchMap(customerObj => 
    this.httpService.getCustomerAccount(customerObj.account_id)
  ),

  switchMap(accountObj =>
    this.httpService.getAccountHoliday(accountObj.holiday_id),
  ),

  map((holidays: Holiday[]) => holidays.map(holiday => 
    this.httpService.getDestination(holiday.dest_id).pipe(
      map(destination => 
        holiday.identifier === destination.name ?
        holiday : null
      )
    )
  )),

  switchMap(mappedHolidays => forkJoin(mappedHolidays)),

  map(mappedHolidays => mappedHolidays.filter(v => v != null))

).subscribe(holidays => holidays.forEach(console.log));

【讨论】:

  • 输出应该是假期,但它们会根据目的地进行过滤。每个假期都有多个目的地,如果holiday.identifier === destination.name 那么假期应该在结果中
  • @asdfkjasdfjk 啊,我明白了。然后几乎是一样的。我更新了我的答案以获得另一种可能的解决方案。
【解决方案2】:

试试这样:

this.httpService
    .getCustomer(id)
    .pipe(
        switchMap((customerObj) => 
            this.httpService.getCustomerAccount(customerObj.account_id)),
        switchMap((accountObj) =>
            this.httpService.getAccountHoliday(accountObj.holiday_id)
                .pipe(
                    switchMap((holiday) => 
                      combineLatest([
                          of(members),                          
                          this.httpService
                              .getDestination(holiday.dest_id)
                      ])
                    ),
                    map(([holiday, dest]) => {
                        if (dest.identifier === dest.name){
                            return holiday
                            /* all holidays not matching the condition 
                            are now undefined */ 
                        }
                    }
                ),
        ),
        map((holidays: (Holiday | undefined)[]) => 
           holidays.filter(h => !!h) // filter out undefined holidays
        ),
     ).subscribe((holidays: Holiday []) => {
         console.log(holidays)  
     });

【讨论】:

  • 输出应该是假期,但它们会根据目的地进行过滤。每个假期都有多个目的地,如果holiday.identifier === destination.name 那么假期应该在结果中
  • 嗯,我看到它仍然无法正常工作,因为第 9 行的假期将是一系列假期
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 2018-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-14
相关资源
最近更新 更多