Javascript 如何在 RxJS 中“等待”两个 observable
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44004144/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to 'wait' for two observables in RxJS
提问by gog
In my app i have something like:
在我的应用程序中,我有类似的东西:
this._personService.getName(id)
.concat(this._documentService.getDocument())
.subscribe((response) => {
console.log(response)
this.showForm()
});
//Output:
// [getnameResult]
// [getDocumentResult]
// I want:
// [getnameResult][getDocumentResult]
Then i get two separated results, first of the _personServiceand then the _documentService. How can I wait for both results before call this.showForm()to finish an then manipulate the results of each one.
然后我得到两个分开的结果,第一个是_personService,然后是_documentService. 如何在调用之前等待两个结果this.showForm()完成然后操作每个结果。
回答by Hamid Asghari
combineLatest(observables) (Update: May, 2020)
combineLatest(observables)(更新:2020 年 5 月)
From reactiveX documentation:
来自reactiveX文档:
Whenever any input Observable emits a value, it computes a formula using the latest values from all the inputs, then emits the output of that formula.
每当任何输入 Observable 发出一个值时,它都会使用来自所有输入的最新值计算一个公式,然后发出该公式的输出。
(Update: May, 2020) While the other example remains valid, here is a new syntax:
(更新: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) (alternate syntax):
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();
})
zip vs combineLatest
zip 与 combineLatest
(Update: Oct, 2018)
I previously suggested the use of zipmethod. However, for some use cases, combineLatesthas a few advantages over zip. So it is important to understand the differences.
(更新:2018 年 10 月)我之前建议使用zip方法。但是,对于某些用例,combineLatest与zip. 因此,了解差异很重要。
CombineLatestemits the latest emitted values from observables. While zipmethod emits the emitted items in sequenceorder.
CombineLatest从 observables 发出最新发出的值。Whilezip方法按顺序发出发出的项目。
For example if observable #1 emits its 3rditem and observable #2 has emitted its 5thitem. The result using zipmethod will be the 3rdemitted values of both observables.
例如,如果 observable #1 发出它的第 3项,而 observable #2 发出它的第 5项。使用zip方法的结果将是两者的第三个发出的值observables。
In this situation the result using combineLatestwill be the 5thand 3rd. which feels more natural.
在这种情况下,使用的结果combineLatest将是5th和3rd。这感觉更自然。
Observable.zip(observables)
Observable.zip(可观察的)
(Original answer: Jul, 2017) Observable.zip method is explained in reactiveX documentation:
(原始答案:2017 年 7 月)reactiveX 文档中解释了 Observable.zip 方法:
Combines multiple Observables to create an Observable whose values are calculated from the values, in order, of each of its input Observables.
组合多个 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();
})
a side note (applies for both methods)
旁注(适用于两种方法)
The last parameter, where we have provided a function, (name: string, document: string) => ({name, document})is optional. You can skip it, or do more complex operations:
我们提供了一个函数的最后一个参数(name: string, document: string) => ({name, document})是可选的。你可以跳过它,或者做更复杂的操作:
If the latest parameter is a function, this function is used to compute the created value from the input values. Otherwise, an array of the input values is returned.
如果最新的参数是一个函数,则该函数用于根据输入值计算创建的值。否则,返回输入值的数组。
So if you skip the last part, you get an array:
所以如果你跳过最后一部分,你会得到一个数组:
// 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();
})
回答by Prathmesh Dali
Use forkJoin()method of observables. Check this link for reference
使用forkJoin()observables 的方法。检查此链接以供参考
From the RXJS docs
来自 RXJS文档
This operator is best used when you have a group of observables and only care about the final emitted value of each. One common use case for this is if you wish to issue multiple requests on page load (or some other event) and only want to take action when a response has been receieved for all. In this way it is similar to how you might use Promise.all
当您有一组 observable 并且只关心每个的最终发出值时,最好使用此运算符。一个常见的用例是,如果您希望在页面加载(或某些其他事件)时发出多个请求,并且只想在收到所有响应时采取行动。通过这种方式,它类似于您使用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];
});
Code taken from: https://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs
代码取自:https: //coryrylan.com/blog/angular-multiple-http-requests-with-rxjs
回答by nyxz
The RxJS Operators for Dummies: forkJoin, zip, combineLatest, withLatestFromhelped me a lot. As the name states it describes the following combination operators:
The RxJS Operators for Dummies: forkJoin, zip, combineLatest, withLatestFrom帮了我很多。顾名思义,它描述了以下组合运算符:
Any of them could be the thing you are looking for, depends on the case. Check the article for more info.
它们中的任何一个都可能是您正在寻找的东西,具体取决于具体情况。查看文章了解更多信息。
回答by Олег Беликов
For me this samplewas best solution.
对我来说,这个样本是最好的解决方案。
const source = Observable.interval(500);
const example = source.sample(Observable.interval(2000));
const subscribe = example.subscribe(val => console.log('sample', val));
So.. only when second (example) emit - you will see last emited value of first (source).
所以..只有当第二个(示例)发出时 - 你会看到第一个(源)的最后发出的值。
In my task, I wait form validation and other DOM event.
在我的任务中,我等待表单验证和其他 DOM 事件。
回答by Kamil Kie?czewski
Improvement of Hamid Asghari answerwhich use direct arguments decomposition and automatically add types (when you use typescript)
使用直接参数分解并自动添加类型的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();
});
BONUS: You can also handle errors using above approach as follows
奖励:您还可以使用上述方法处理错误,如下所示
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();
});
回答by Tal
Have a look at the 'combineLatest' method, it might be appropriate here. http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-combineLatest
看看'combineLatest'方法,它可能适合这里。 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()
})
回答by thatseeyou
You can use 'zip' or 'buffer' like the following.
您可以使用“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}`));

