如何在RxJS中“等待”两个可观察对象


76

在我的应用程序中,我有类似以下内容:

this._personService.getName(id)
      .concat(this._documentService.getDocument())
      .subscribe((response) => {
                  console.log(response)
                  this.showForm()
       });

 //Output: 
 // [getnameResult]
 // [getDocumentResult]

 // I want:
 // [getnameResult][getDocumentResult]

然后我得到两个分开的结果,首先是_personService,然后是_documentService。如何在调用this.showForm()完成之前等待两个结果,然后操纵每个结果。


2
forkJoingithub.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/…–
朱莉娅·

据我了解,您已经凭借concat
user3743222

@ user3743222在这种情况下,这些值是分别发出的。一个接一个
高格

1
在forkJoin中,subscribe将得到一个结果-具有第一和第二个响应的元组-这正是您所要求的?
朱莉娅·帕森科娃

Answers:


107

最后更新:2020年5月。

CombineLatest(observables)

从reactX文档中

每当任何Observable输入发出值时,它都会使用来自所有输入的最新值来计算公式,然后发出该公式的输出。

(更新:2020年5月)尽管另一个示例仍然有效,但这是一个新语法:

// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

name$.combineLatest(document$, (name, document) => {name, document})
    .subscribe(pair => {
           this.name = pair.name;
           this.document = pair.document;
           this.showForm();
       })

CombineLatest(observables)(替代语法):

// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

combineLatest(name$, document$, (name, document) => ({name, document}))
    .subscribe(pair => {
           this.name = pair.name;
           this.document = pair.document;
           this.showForm();
       })

拉链vs组合最新

(更新:2018年10月) 我以前建议使用zip方法。但是,对于某些用例,combineLatest与相比有一些优势zip。因此,了解差异非常重要。

CombineLatest从可观察对象发出最新的发出值。Whilezip方法顺序发射发射的项目。

例如,如果可观察的#1发出其第三项,而可观察的#2发出其第五项。使用zip方法的结果将是两者的第三个发射值observables

在这种情况下,使用的结果combineLatest将是5th3rd。感觉更自然。


Observable.zip(observables)

(原始答案:2017年7月) Observable.zip方法在reactX文档中进行了解释:

组合多个Observable来创建一个Observable,其值是根据其每个输入Observable的值依次计算得出的。

// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

Observable
    .zip(name$, document$, (name: string, document: string) => ({name, document}))
    .subscribe(pair => {
           this.name = pair.name;
           this.document = pair.document;
           this.showForm();
       })

旁注(适用于两种方法)

我们提供函数的最后一个参数(name: string, document: string) => ({name, document})是可选的。您可以跳过它,或执行更复杂的操作:

如果最新参数是一个函数,则此函数用于从输入值中计算创建的值。否则,将返回输入值的数组。

因此,如果跳过最后一部分,则会得到一个数组:

// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

Observable
    .zip(name$, document$)
    .subscribe(pair => {
           this.name = pair['0'];
           this.document = pair['1'];
           this.showForm();
       })

是否可以使用this等待一个可观察对象的完成,而我的可观察对象又具有另一个内部可观察对象,而后者又依赖于http.get?
HDJEMAI

在2020年1月的更新中,为什么将数组映射到对象?当您可以在subscription方法中销毁数组时,这似乎是不必要的步骤。那是我唯一的评论,其余的看起来不错。
Craig Myles

OOOOHHHH,我一个小时想找CombineLatest操作员...非常感谢
Andrew

您如何退订合并的可观察物?只是取消订阅CombinedLatest()。subscribe()返回的可观察对象?
sharon182

完全是@ sharon182。
哈米德·阿斯加里

36

forkJoin()观测值的使用方法。检查此链接以供参考

来自RXJS文档

当您有一组可观测对象并且仅关心每个可观测对象的最终发射值时,最好使用此运算符。一种常见的用例是,如果您希望在页面加载(或其他事件)时发出多个请求,并且只希望在收到所有响应后才采取措施。这样类似于您使用Promise.all的方式

Observable.forkJoin([character, characterHomeworld]).subscribe(results => {
  // results[0] is our character
  // results[1] is our character homeworld
  results[0].homeworld = results[1];
  this.loadedCharacter = results[0];
});

代码取自:https : //coryrylan.com/blog/angular-multiple-http-requests-with-rxjs


是否可以使用this等待一个可观察对象的完成,而我的可观察对象又具有另一个内部可观察对象,而后者又依赖于http.get?
HDJEMAI

@HDJEMAI如果您想做某事。完成一项可观察的工作后,可以使用嵌套订阅吗?
Yuwei HE


5

Hamid Asghari答案的改进,它使用直接参数分解并自动添加类型(使用打字稿时)

const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

combineLatest([name$, document$]).subscribe(([name, document]) => {
    this.name = name;
    this.document = document;
    this.showForm();
});

奖励:您还可以使用以下方法处理错误,如下所示


2

对我而言,此样本是最佳解决方案。

const source = Observable.interval(500);
const example = source.sample(Observable.interval(2000));
const subscribe = example.subscribe(val => console.log('sample', val));

所以..仅当第二个(示例)发出时-您将看到第一个(源)发出的最后一个值。

在我的任务中,我等待表单验证和其他DOM事件。


1

看一看“ combineLatest”方法,这里可能合适。 http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-combine最新

const { Observable } = Rx

const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

Observable
    .combineLatest(name$, document$, (name, document) => ({ name, document }))
    .first() // or not, implementation detail
    .subscribe(({ name, document }) => {
        // here we have both name and document
        this.showForm()
    })

0

您可以使用“ zip”或“ buffer”,如下所示。

function getName() {
    return Observable.of('some name').delay(100);
}

function getDocument() {
    return Observable.of('some document').delay(200);
}

// CASE1 : concurrent requests
Observable.zip(getName(), getDocument(), (name, document) => {
    return `${name}-${document}`;
})
    .subscribe(value => console.log(`concurrent: ${value}`));

// CASE2 : sequential requests
getName().concat(getDocument())
    .bufferCount(2)
    .map(values => `${values[0]}-${values[1]}`)
    .subscribe(value => console.log(`sequential: ${value}`));
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.