0

所以,我试图绕开我的脑袋rxjs/observable,在我的测试案例研究中,我试图构建一个简单的基于 angular(5) 的 web 应用程序,它应该显示一些关于地理实体的统计信息,即国家、州、城市。所以我创建changeView了一个接受三个参数(两个可选)和各自 id 的方法。
一开始我希望应用程序首先检查我的模型是否已经加载了国家数据,如果没有则查询数据,将检索到的数据保存在模型中,然后检查是否stateId已指定并包含在country.states数组中检查是否已经加载,如果不查询状态等等,直到检索到所有数据,或者用户更改了输入参数,在这种情况下,所有正在进行的请求都应该停止(据我了解,这部分已完成经过switchMap操作员),新一轮的请求应该开始。几天后我明白这太复杂了,所以我改变了计划,决定只在最后才将数据存储到模型中。它看起来像我想要的那样,但子顺序请求并没有被取消。以下是我目前所拥有的摘录:

of({countryId: 1, stateId: 1, cityId: 1}).pipe(
  debounceTime(500),
  switchMap(newState => {
    if ((newState !== null))
    {
     return this.geoStatsService.getCountry(newState.countryId);
    }
    else
    {
     return empty();
    }
  }, (outerValue, innerValue) => {
    if ("stateId" in outerValue && outerValue.stateId !== undefined)
    {
     // ToDo: Check that state is located in this county
     return forkJoin(of(innerValue), this.geoStatsService.getStates(outerValue.stateId));
    }
    else
    {
     return of(innerValue);
    }
  }),
  mergeAll()
  ).subscribe(res => {
     console.debug("---Subscription---");
     console.debug(res);
  });

我已经看到,一旦第二个请求被触发,它就不会被取消,并且数据将进入订阅......在我看来我过于复杂了,它可以更优雅地完成方式,这也将按我的预期工作,是这样吗?附加问题:我可以,或更准确的问题 - 我应该从流程中提取数据,还是仅在订阅方法中提取数据?

4

2 回答 2

1

嗯...鉴于 Country/State/City 可能都需要加载,在我看来,您需要的是 3 个嵌套的 switchMap,如下所示:

interface Query { countryId: number; stateId?: number; cityId?: number }

// keep a cache to avoid reloading
const countryCache = new Map<number, Country>();
const stateCache = new Map<number, State>();
const cityCache = new Map<number, City>();

const query$: Observable<Query> = of({countryId: 1, stateId: 1, cityId: 1});

query$.pipe(
  debounceTime(500),
  switchMap((q: Query) => {
    if (!q || q.countryId === undefined) {
      return of([]);
    }

    // get country from cache or load from backend
    const country$ = countryCache.has(q.countryId) ?
      of(countryCache.get(q.countryId)) :
      this.geoStatsService.getCountry(q.countryId).do(country => {
        countryCache.set(q.countryId, country);
      });

    return country$.pipe(
      switchMap(country => {
        if (!country || !country.states.includes(q.stateId)) {
          return of([country]);
        }

        // get state from cache or load from backend
        const state$ = stateCache.has(q.stateId) ?
          of(stateCache.get(q.stateId)) :
          this.geoStatsService.getState(q.stateId).do(state => {
            stateCache.set(q.stateId, state);
          });

        return state$.pipe(
          switchMap(state => {
            if (!state || !state.cities.includes(q.cityId)) {
              return of([country, state]);
            }

            // get city from cache or load from backend
            const city$ = cityCache.has(q.cityId) ?
              of(cityCache.get(q.cityId)) :
              this.geoStatsService.getCity(q.cityId).do(city => {
                cityCache.set(q.cityId, city);
              });

            return city$.map(city => [country, state, city]);
          })
        );
      })
    );
  })
).subscribe(([country, state, city]) => {
  // ...
});
于 2018-02-15T03:58:38.600 回答
0

尝试使用“flatMap”而不是“switchMap”,switchMap 有自己的取消系统,这就是为什么有时你不会得到订阅的原因。

https://www.learnrxjs.io/operators/transformation/switchmap.html

顺便说一句,您必须订阅,否则代码将无法运行。

于 2018-02-15T07:12:41.267 回答