Rxjs:Observable.combineLatest与Observable.forkJoin


84

只是想知道Observable.combineLatest和 之间有什么区别Observable.forkJoin?据我所知,唯一的区别是forkJoin期望Observables完成,同时combineLatest返回最新值。


4
注:在rxjs6 +这些现在只是combineLatest()forkJoin()创造可观察到的功能。它们的作用相同,但语法不同。不要混淆combineLatestrxjs/operators哪个是“pipeable”操作。如果您输入的是错误的,将会出错。
Simon_Weaver

Answers:


126

不仅forkJoin要求完成所有输入可观察值,而且还返回产生单个值的可观察值,该值是输入可观察值产生的最后一个值的数组。换句话说,它等待直到最后一个可观察输入完成,然后生成一个值并完成。

相反,combineLatest一旦所有输入可观测值都产生了至少一个值,则每次输入可观测值返回时都会返回一个产生新值的Observable。这意味着它可能具有无限值,并且可能无法完成。这也意味着输入可观察值在产生值之前不必完成。


@GregL是否有一个类似于forkJoin的函数,但是也会在失败的http调用下起作用?
Tukkan

2
@Tukkan,我将把从错误中恢复的运算符链接到每个http可观察的对象,以便您定义要用于每个错误请求的值,而不是查找将多个可能出错的可观察对象组合在一起的操作员(I '不确定是否存在这样的运算符)。从错误中恢复的运算符包括.catch(),,.onErrorResumeNext()并且可能包括.retry()(如果Http调用可能间歇性地失败)。
GregL

1
只是为了澄清,它们都产生数组。
Simon_Weaver

@Simon_Weaver不一定。对于combineLatest(),您可以提供投影函数以指定如何从输入可观察值的最新值中产生输出值。默认情况下,如果您不指定一个,则将获得一个最新发射值的数组。
GregL

CombineLatest的每个发射都是收集值的数组。我只是想补充一下,因为您只提到了forkjoin的数组。因此,它们是相同的。是的,RxJS总是有一些细微之处,所以如果我错过了什么,您可以弄清您的意思了。
Simon_Weaver

14

也:

CombineLatest(...)依次运行可观察对象

combineLatest内部使用concat,这意味着必须在移动到下一个数组之前为数组中的每个可观察值获取一个值。

// partial source of static combineLatest (uses the rxjs/operators combineLatest internally):
// If you're using typescript then the output array will be strongly typed based on type inference
return function (source) { return source.lift.call(from_1.from([source].concat(observables)), 
                           new combineLatest_1.CombineLatestOperator(project)); };

forkJoin(...)同时并行运行可观察对象

如果您有3个源可观察物,并且它们分别需要5秒钟才能运行,那么将需要15秒钟combineLatest才能运行。而forkJoin它们是并行执行的,因此需要5秒钟。

因此,其forkJoin工作方式更像Promise.all(...)是不执行命令的地方。

错误处理注意事项:

如果有任何可观察的错误,combineLatest则不会执行-后续的将不会执行,但是forkJoin它们都在运行。因此combineLatest,执行可观察值的“序列”并一起收集结果可能很有用。


高级说明:如果源可观测对象已经在“运行”(由其他对象订阅)并且正在使用share它们-那么您将不会看到此行为。

更高级的注释:CombineLatest将始终为您提供每个来源的最新信息,因此,如果其中一个来源可观察对象发出多个值,您将获得最新信息。它不仅为每个源获取一个值,然后移至下一个。如果需要确保每个可观察.pipe(take(1))到的源仅获得“下一个可用项”,则可以在将其添加到输入数组时将其添加到可观察到的源。


感谢您处理错误的注意事项。在多个可观察对象的情况下,错误处理很难理解。
D Deshmane

2
我相信您误解concat()combineLatest()代码中的行为。在我看来,该Array.prototype.concat方法不是RxJSconcat方法。假设我是对的,那么这个答案是误导性的和不正确的,因为combineLatest()不会按顺序逐个执行可观察项。它与并行执行它们forkJoin()。不同之处在于产生了多少值,以及源可观测值是否必须完成。
GregL

@GregL Array.concat对于可观察对象毫无意义。我绝对依赖concat的顺序性质-要理解的关键是,在执行所有输出值之前,您不会获得任何输出值。
Simon_Weaver

我在您发布的示例源代码中引用了此代码[source].concat(observables),假设这就是您在说“combineLatest内部使用concat”时的意思。在我看来,您似乎将数组concat与RxJS concat混淆了。后者确实按顺序执行输入的可观察对象,直到它们完成为止。但这并不是combineLatest(),完全是一个单独的运算符。
GregL

3
我相信combineLatest()forkJoin()两者并行运行。运行下面的代码,两者都输出约5000。 const start = new Date().getTime(); combineLatest([of(null).pipe(delay(5000)), of(null).pipe(delay(5000)), of(null).pipe(delay(5000))]).subscribe(() => console.log(new Date().getTime() - start)); forkJoin([of(null).pipe(delay(5000)), of(null).pipe(delay(5000)), of(null).pipe(delay(5000))]).subscribe(() => console.log(new Date().getTime() - start));
杰里米

12

forkJoin-完成所有可观察值后,从每个观察值中发出最后一个发出的值。

CombineLatest-当任何可观察对象发出值时,从每个观察对象发出最新值。

用法非常相似,但是与forkJoin不同,您不应该忘记退订 CombineLatest


1
如果一个请求失败,所有嵌套的请求会自动取消,该如何解决?
Sunil Garg,

1
@SunilGarg如果只想获取所有结果,则应使用forkJoin或CombineLatest。如果您不关心所有结果,则应单独使用订阅。
Dmitry Grinko '19年


您能否通过代码示例解释为什么需要取消订阅
Sunil Garg,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.