RxJs阶梯式链式调用Observable。

3

之前我在Typescript中使用Promise与async/await语法,如下所示

const fooData = await AsyncFooData();
const barData = await AsyncBarData();

... do something with fooData and barData

如果我使用 RxJs 的 Observable<T>,对我来说会变成这样

AsyncFooData().subscribe(fooData => {
   AsyncBarData().subscribe(barData => {
      ... do something with fooData and barData
   })
})

有没有更好的方法来处理这个问题?因为如果我需要处理更多的AsyncData,它就会变得难以阅读,就像Staircase一样。

3个回答

3

你不能像使用 async/await 一样轻松地完成此操作,因为你仍然需要有 .subscribe 回调函数,并且可能会有多个属性被发出。你应该永远不要嵌套 .subscribe 调用。通常,你会使用高阶 Observable 操作符,如 mergeMap,或一个将多个 Observables 的发射同步在一起的 Observable 创建器,例如 combineLatest:

combineLatest(AsyncFooData(), AsyncBarData()).subscribe([fooData, barData] => {

});

你需要的确切函数取决于你自己的需求以及 foobar 的发射方式:
  • combineLatest - 每当任何源发出时均会发出(注意:只有在所有源发出一次后才开始发出)。
  • zip - 同步发射,例如每个 Observable 发射一次就会发射一次,然后两次,以此类推。
  • forkJoin - 当所有源 observable 完成时发出。
  • merge - 每当任何源发出时均会发出。不像上面的那些,它不会组合输出。

还有更多可用的内容:https://www.learnrxjs.io/operators/combination/


谢谢你的建议,我最终使用了你建议的运算符。我觉得我的代码变得更好了 :) - starcorn
在您的情况下@starcorn,由于您的函数似乎是promises,请使用forkJoin。Promises总是完成的。 - Quentin Fonck

2

我认为您正在寻找一种更加“干净”的方式来链接多个异步操作。这是我的做法:

  • 我使用了from(),因为我假设AsyncFooData返回一个Promise。如果它返回Observable,请删除from()
  • 避免多个订阅(通常比我们想象的要少)。
  • 使用pipe()来链接适当的操作符,可以按照需要以相当平坦的方式链接多个操作符。
  • subscribe()在所有操作完成后调用。
  • Style A将foo的结果传递到subscribe的next函数中。
  • Style B仅适用于最后一个异步操作的结果。

注意:这些示例是为了分享概念/方法而编写的,没有进行IDE语法检查。这个概念应该是可行的,但如果有语法错误,敬请谅解。

// A: if you need both foo and bar
from(AsyncFooData()).pipe(
  concatMap(foo => AsyncBarData().pipe(
    map(bar => ({foo, bar})
  )),
  tap(val => console.log(val), // chain more operators here...
).subscribe(({foo, bar}) => {
  // do stuff with foo and bar
})

// B: if foo is only used to get bar (i.e. no need to pass it along)
from(AsyncFooData()).pipe(
  concatMap(foo => AsyncBarData(foo)), // assume foo is only used to get bar
  tap(val => console.log(val), // chain more operators here...
).subscribe(bar => {
  // do stuff with bar
})

谢谢你的建议,我使用了你提供的运算符解决了问题。虽然代码有点长,但我不再使用subscribe,而且代码也不像阶梯一样了。 - starcorn

1
你可以使用 zip 压缩并获取 fooDatabarData,然后进行任何你想做的操作。
zip(AsyncFooData(), AsyncBarData()).subscribe([fooData, barData]) => {})

这里以zip为例。根据您的需要,您可以使用其他运算符,例如combineLatest
我不会在此解释zipcombineLatest和其他运算符之间的区别,因为这样做可能会使答案变得混乱。相反,我指出以下资源,其中用图表和示例清楚地解释了这些内容:
(1) 官方文档 (2) 弹珠图

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接