微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我们应该避免嵌套的 rxjs 操作符吗?我无法测试的一种情况

如何解决我们应该避免嵌套的 rxjs 操作符吗?我无法测试的一种情况

我在使用 rxjs 的 Angular 应用程序中编写了以下效果。在 MyActions.myAction 上,我收到一个包含属性 ids 的对象 - 一个 id 数组 - 对于每个 id 我想通过 this.myApiService.getResource 发送一个 HTTP 请求,它返回一个 {{1} }.然后我想将所有结果收集到一个数组中,然后调度另一个传递该数组的操作。

Observable<Resource>

上面的代码完成了这项工作,但我想知道我是否应该避免嵌套两个响应式操作符流,以及是否有更好的编写方法

我想知道的原因是我在为它编写测试时遇到了问题。我写了下面的测试,但我无法通过。

  public loadResources$: Observable<MyAction> = this.actions$.pipe(
    ofType(MyActions.myAction),switchMap(({ ids }) => from(ids).pipe(
      mergeMap(id => this.myApiService.getResource(id)),toArray()
    )),map(resources) => MyActions.resourcesLoaded({ resources } )),);

我得到的错误是:

 it('should dispatch an resourcesLoaded action with the resources',() => {
      const ids = ['5f7c723832758b859bd8f866'];
      const resources = [{} as Resource];

      const values = {
        l: MyActions.loadResources({ ids }),t: ids[0],o: MyActions.resourcesLoaded({ resources })
      };

      actions =         hot('--l------------',values);
      const get$ =     cold('  -------t-----',values);
      const expected = cold('---------o-----',values);

      myApiService.getResource.withArgs(ids[0]).returns(get$);

      expect(myEffects.loadResources$).toBeObservable(expected);
    });

解决方法

我发现我的测试失败了,因为 toArray 正在等待 getResource(即 httpClient.get)返回的 observable 完成。用 t 替换 (t|) 修复了测试:

 it('should dispatch an resourcesLoaded action with the resources',() => {
      const ids = ['5f7c723832758b859bd8f866'];
      const resources = [{} as Resource];

      const values = {
        l: MyActions.loadResources({ ids }),t: ids[0],o: MyActions.resourcesLoaded({ resources })
      };

      actions =         hot('--l------------',values);
      const get$ =     cold('  -------(t|)-----',values);
      const expected = cold('---------o-----',values);

      myApiService.getResource.withArgs(ids[0]).returns(get$);

      expect(myEffects.loadResources$).toBeObservable(expected);
    });

然而,我问题的第一部分,即像这样嵌套操作符是否是好的做法,仍然有效。

,

但我想知道我是否应该避免嵌套两个反应式运算符流,以及是否有更好的方法来编写

我认为这取决于您想要实现的目标,至少在这种情况下是这样。

of([1,2,3]).pipe(mergeAll(),switchMap(value => http.get(...)))

不同于

of([1,3]).pipe(switchMap(ids => from(ids).pipe(mergeMap(...))))

在第一种情况下,每个内部 observable 都会被下一个值(最后一个值除外)丢弃,因此只有 3 个会被解析。
在第二种情况下,它将处理所有这些,因为您在内部 observable(由 swtichMap 管理,因此其内部 observable 将被丢弃的唯一方法是如果一个新的外部值(例如另一个 id 数组)由源发出)。

不需要嵌套的情况是:

of([1,3])
  .pipe(
    // whenever you want to explode an array,// it does not matter which higher order operator you use
    // since the operation is **synchronous**
    // so,`mergeAll`,`concatAll`,`switchAll` should work the same
    mergeAll(),mergeAll(id => this.apiService.useId(id))
  )

// same as

of([1,3])
  .pipe(
    mergeMap(ids => from(ids).pipe(mergeMap(id => this.apiService.useId(id))))
  )

如您所见,在本例中,switchMap 已替换为 mergeMap

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。