使用RxJS Observables时Promise.all的行为是怎样的?

119

在 Angular 1.x 中,有时我需要进行多个 http 请求并处理所有响应。 我会将所有的 promise 放入一个数组中,并调用 Promise.all(promises).then(function (results) {...})

Angular 2 的最佳实践似乎是使用 RxJS 的 Observable 来替代在 http 请求中使用 promise。 如果我有两个或多个不同的 Observables 从 http 请求生成,是否有与 Promise.all() 相当的等效方法?


Promise.all() with RxJS 的副本 - BuZZ-dEE
@BuZZ-dEE 考虑到这个问题有5倍的赞同和3倍的浏览量,也许早先提出的那个应该被标记为重复? - Corey Ogburn
我认为后面的问题是重复的。我认为这个问题有更多的赞和浏览量并不重要。 - BuZZ-dEE
4个回答

98

1
如果我有两个调用,一个返回Promise,另一个返回Observable,我可以使用forkJoin吗?还是Promise.all()?或者都不行,我必须让这两个函数返回相同类型的Promise或Observable? - Joe Sleiman
1
请帮忙,当作为参数传递的可观察对象不发出值时,forkJoin无法工作。我有空的Observables,仍然想使用forkJoin功能,但它不起作用。 - Goga Koreli

31

2019年5月的更新,使用RxJs v6

我发现其他答案很有用,并希望为Arnaud提供的关于zip用法的答案提供一个示例。

这是一段代码片段,展示了Promise.all和rxjs的zip之间的等效性(请注意,在rxjs6中,zip现在使用"rxjs"导入,而不是作为运算符导入)。

import { zip } from "rxjs";

const the_weather = new Promise(resolve => {
  setTimeout(() => {
    resolve({ temp: 29, conditions: "Sunny with Clouds" });
  }, 2000);
});

const the_tweets = new Promise(resolve => {
  setTimeout(() => {
    resolve(["I like cake", "BBQ is good too!"]);
  }, 500);
});

// Using RxJs
let source$ = zip(the_weather, the_tweets);
source$.subscribe(([weatherInfo, tweetInfo]) =>
  console.log(weatherInfo, tweetInfo)
);

// Using ES6 Promises
Promise.all([the_weather, the_tweets]).then(responses => {
  const [weatherInfo, tweetInfo] = responses;
  console.log(weatherInfo, tweetInfo);
});

两者的输出结果相同。运行上述代码将得到:

{ temp: 29, conditions: 'Sunny with Clouds' } [ 'I like cake', 'BBQ is good too!' ]
{ temp: 29, conditions: 'Sunny with Clouds' } [ 'I like cake', 'BBQ is good too!' ]

是否存在一个重要的区别,这导致建议使用Observables而不是简单的Promise.all()? - Harshal

13

forkJoin也可以正常运行,但我更喜欢combineLatest,因为你不必担心它获取 observables 的最后一个值。这样,只要它们中的任何一个发出新的值(例如在时间间隔上获取),您就可以获得更新。


1
这不符合我的当前需求,但我肯定很快会使用它。 - Corey Ogburn
6
这并不能达到与Promise.all()相同的行为,但它与Promise.any()类似。 - Purrell
如果我有两个调用,一个返回Promise,另一个返回Observable,我可以使用forkJoin吗?还是Promise.all()?或者都不行,我必须让这两个函数返回相同类型的Promise或Observable? - Joe Sleiman
1
@JoeSleiman 有点晚了,但你可以选择你的方案:Observable.fromPromise()Observable.zip(),或者使用 Obserable.toPromise() 和 Promise.all()。 - Arnaud P

13

reactivex.io 上,forkJoin 实际上指向了 Zip,而这对我来说已经足够了:

let subscription = Observable.zip(obs1, obs2, ...).subscribe(...);

这意味着forkJoin不会发出超过一次的值,并且在此之后它将完成。如果您需要在传递的可观察对象的生命周期结束时以及在其整个生命周期中发出组合值,请尝试使用combineLatest或zip。 - Jeffrey Nicholson Carré
5
forkJoin 等待所有可观察对象完成,而 zip 在所有输入都发出第一个值时发出数组。zip 可能会多次发出。如果有 http-calls,这并不重要。 - hgoebl
好的,现在我明白了,谢谢。我之前没意识到语言部分可以展开。-_- - Arnaud P

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