【问题标题】:RxJs - Having trouble resolving observable streamRxJs - 无法解析可观察的流
【发布时间】:2019-09-28 21:03:48
【问题描述】:

所以我有一个 NgRx 选择器,它返回一个带有联系人数组的 Observable。我想映射这个流,并且对于每个联系人数组,映射每个单独的联系人并向 Github 发出 Http 请求以获取他们的个人资料图像,并将其附加到 Contact 对象。但是,如果不以 Observable 数组的 Observable 结尾,我不确定如何做到这一点。

以下是我尝试过的,但这不起作用。

this.contacts$: Observable<Contact[]> = this.store.select(getContacts).pipe(
  map(contacts => {
    return contacts.map(contact => {
      return this.contactService.getGithub$(contact._id).pipe(
        map(githubInfo => {
          return {
            ...contact,
            imageUrl: githubInfo.avatar_url
          };
        })
      );
    });
  })
);

以下是我收到的错误消息:

Type 'Observable<Observable<Contact>[]>' is not assignable to type 'Observable<Contact[]>'.
  Type 'Observable<Contact>[]' is not assignable to type 'Contact[]'.
    Type 'Observable<Contact>' is missing the following properties from type 'Contact': first_name, last_name, job_title, location, company ts(2322)

任何建议将不胜感激!

【问题讨论】:

    标签: angular rxjs observable


    【解决方案1】:

    使用switchMap 将您的contacts 数组映射到一个Observable,该Observable 同时执行您的http 请求并将它们映射到一个扩展的Contact 对象。

    this.contacts$: Observable<Contact[]> = this.store.select(getContacts).pipe(
      switchMap(contacts => forkJoin(
        contacts.map(contact => this.contactService.getGithub$(contact._id).pipe(
          map(gitHubInfo => ({ ...contact, imageUrl: githubInfo.avatar_url }))
        ))
      ))
    );
    

    【讨论】:

      【解决方案2】:

      这里的问题是您正在运行一个Array.map,它为每个contact 返回一个 Observable。如果你想让 Observable 返回完整的数组,你会想要这样的:

      this.contacts$: Observable<Contact[]> = this.store.select(getContacts).pipe(
        // take the array and emit each value one by one
        concatMap(contacts => from(contacts)),
        // emit an array containing the contact and the corresponding githubInfo
        concatMap(contact => forkJoin(of(contact), this.contactService.getGithub$(contact._id))),
        // take the returned array and convert it to an Object
        map(([contact, githubInfo]) => ({ ...contact, imageUrl: githubInfo.avatar_url})),
        // concatenate everything into a final Array
        toArray()
      );
      

      我必须承认我是在旅途中写的,因此没有测试它,但我认为它应该可以工作!

      如果保持原始顺序很重要,请保留concatMap。如果没有,请使用mergeMap 来提高性能。

      【讨论】:

      • 谢谢,威尔!这非常接近,但由于某种原因它没有发出任何值。如果我删除 toArray(),它会发出带有正确 imageUrl 的单独值。
      • 我相信流需要完成 toArray() 才能工作
      • 你的选择器应该在它发出所有值后完成,不是吗?
      • 嗯,它是一个记忆选择器,只要 NgRx 存储值发生变化,它就会重新发出联系人数组。所以它永远不会真正完成。我可能错了,但我相信这就是它的工作原理。
      • 你完全正确,对不起!我没有用 NgRx 的术语来思考!如果你真的需要一个数组,你有几个可能的选择。您可以使用扫描/减少策略,或者在提取原始联系人数组的长度后添加takeUntil。这有意义吗?
      【解决方案3】:
      this.contacts$: Observable<Contact[]> = this.store.select(getContacts).pipe( 
          map(contacts => {
              return contacts.map(contact => {
                  return this.contactService.getGithub$(contact._id).pipe(
                      map(githubInfo => {
                          return { ...contact, imageUrl: githubInfo.avatar_url };
                      })
                  );
              });
          }),
          concatAll()
      );
      

      只需将concatAll 运算符添加到管道流。

      【讨论】:

      • 没有格式或解释的答案是没有帮助的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-15
      • 1970-01-01
      • 1970-01-01
      • 2019-10-18
      • 2016-05-17
      • 2017-06-11
      • 2016-10-29
      相关资源
      最近更新 更多