如何等待'对于RxJS中的两个可观察者

时间:2017-05-16 14:22:08

标签: javascript angular rxjs reactive-programming

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

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()之前等待两个结果然后操作每个结果。

8 个答案:

答案 0 :(得分:50)

更新:2018年10月

我之前建议使用zip方法。但是,从那以后我发现自己使用了combineLatest。所以决定添加combineLatest

CombineLatest会从observable发出最新的值。虽然zip方法会以 序列 顺序排放发出的项目。

例如,如果可观察#1发出其第3 项,则可观察#2已发出其第5 项。使用zip方法的结果将是observables第三次发布值。

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

combineLatest(观测值)

来自reactiveX documentation

  

只要任何输入Observable发出一个值,它就会使用所有输入中的最新值计算公式,然后发出该公式的输出。

// 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();
       })

Observable.zip(观测值)

Observable.zip方法在reactiveX documentation中解释:

  

组合多个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();
       })

答案 1 :(得分:21)

使用forkJoin()可观察方法。 Check this link for reference

来自RXJS docs

  

当您拥有一组可观察对象并且只关心每个可观察对象的最终发射值时,最好使用此运算符。一个常见的用例是,如果您希望在页面加载(或其他一些事件)上发出多个请求,并且只希望在收到所有响应后执行操作。这样,它与您使用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

答案 2 :(得分:5)

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

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();
});

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

import { combineLatest, of } from 'rxjs';
//...

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

combineLatest([
  name$.pipe(     catchError( () => of(null as string  ) ) ), 
  document$.pipe( catchError( () => of(null as Document) ) ), // 'Document' is arbitrary type
]).subscribe(([name, document]) => {
    this.name = name;          // or null if error
    this.document = document;  // or null if error
    this.showForm();
});

答案 3 :(得分:4)

RxJS Operators for Dummies: forkJoin, zip, combineLatest, withLatestFrom对我有很大帮助。顾名思义,它描述了以下组合运算符:

根据情况,其中任何一个都是您要寻找的东西。查看文章以获取更多信息。

答案 4 :(得分:3)

对我来说,sample是最佳解决方案。

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

所以..只有当第二个(例子)发出时 - 你会看到第一个(源)的最后一个值。

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

答案 5 :(得分:1)

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

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()
    })

答案 6 :(得分:0)

您可以使用' zip'或者'缓冲区'如下。

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}`));

答案 7 :(得分:0)

2021 年 6 月

使用 rxjs 6.6.7

像这样使用 combineLatest 否则会被破坏

combineLatest([a$ , b$]).pipe(
      map(([a, b]) => ({a, b})) //change to [a , b] if you want an array
    )

另见@nyxz 帖子

<块引用>

zip - 爱情鸟,总是作为一个团队工作,只有当所有 observables 返回新值

combineLatest - 荷兰语,一旦所有可观察值开始触发 返回新值,然后等待无人,每次触发 要么 observable 返回新值。

withLatestFrom - 主从,主先等待从,后 也就是说,每次只有当主人返回新的时候才会触发动作 价值。

forkJoin - 最终目的地,当所有 observables 时触发一次 已经完成。

来自:https://scotch.io/tutorials/rxjs-operators-for-dummies-forkjoin-zip-combinelatest-withlatestfrom/amp