在 RxJS pipable 运算符之间传递数据的最佳方式?

Best way to pass data between RxJS pipable operators?

除了在 RxJS 的下一个 pipable 运算符中获取其响应数据外,我还想传递 URL。您认为实现这一目标最明智的方法是什么? 提前致谢。

这是一个例子。 https://stackblitz.com/edit/angular-rxjs-passing-data-to-next-operator-question

我尝试了一些运算符,但找不到合适的。 (实际上,我什至不知道为什么将 returns 可观察到的函数传递给 mergeMap 会导致在下一个运算符中将数据作为函数的参数...)

from([
  'https://jsonplaceholder.typicode.com/posts',
  'https://jsonplaceholder.typicode.com/comments',
  'https://jsonplaceholder.typicode.com/albums',
])
  .pipe(
    mergeMap(url => this.getData(url)),
    tap(posts => console.log(posts[0])), // I want to get url too here!!
  ).subscribe();

我希望在 pipable 运算符中得到 url 及其响应数据。

您可以将响应映射到您想要的任何内容:

from([
  'https://jsonplaceholder.typicode.com/posts',
  'https://jsonplaceholder.typicode.com/comments',
  'https://jsonplaceholder.typicode.com/albums',
]).pipe(
    mergeMap(url => this.getData(url).pipe(
      map(response => ({ response, url })),
    )),
    tap(response => console.log(response)),
  ).subscribe();

查看mergeMapmergeMap(project: function: Observable, resultSelector: function: any, concurrent: number): Observable的签名,可以使用resultSelector参数:

from([
  'https://jsonplaceholder.typicode.com/posts',
  'https://jsonplaceholder.typicode.com/comments',
  'https://jsonplaceholder.typicode.com/albums',
])
  .pipe(
    mergeMap(url => 
      this.getData(url),
      (outerValue, innerValue) => ({ url: outerValue, posts: innerValue })),
    tap(({ posts, url })=> {
      console.log(posts);
      console.log(url);
    })
  ).subscribe();

这将有效地将 urlthis.getData(url) 的结果映射到可在 tap() 中使用的对象。

这是您的 example 修改后的实际效果。

注意: 结果选择器在 process of being deprecated/removed 中。虽然此解决方案目前可能有效,但在未来的 RxJS 版本中将不再可行 (7.x)。 @martin提供的答案肯定更"future-proof".

希望对您有所帮助!

Martin 的答案对于给定的代码示例是正确的。

然而,对于更复杂和更长的运算符链,将先前的值传递给后续运算符可能会成为一项相当复杂的任务。尤其是在使用扩展运算符等更高级的运算符时。

在那些情况下,我更喜欢使用闭包来存储这些值:

const myStream$ = () => {
   const urls = [
      'https://jsonplaceholder.typicode.com/posts',
      'https://jsonplaceholder.typicode.com/comments',
      'https://jsonplaceholder.typicode.com/albums',
  ];
  let dataUrl;
  return from(urls).pipe(
      mergeMap(url => {
         dataUrl = url;
         return this.getData(url)
      }),
    // ... assuming more operators are called here ... //
    tap(posts => console.log(posts[0], dataUrl))
  );
};

myStream$().subscribe();

但同样,对于更简单的运算符链,向返回的对象添加值是可行的方法。