javascript - observables - rxjs observable
Cómo ''esperar'' por dos observables en RxJS (5)
Actualización: Oct, 2018
Anteriormente sugerí el uso del método zip
. Sin embargo, desde entonces me encontré usando combineLatest
en combineLatest
lugar. Así que decidí agregar combineLatest
.
CombineLatest
emite los últimos valores emitidos de los observables. Mientras que zip
método zip
emite los elementos emitidos en orden de secuencia .
Por ejemplo, si el observable # 1 emite su tercer elemento y el observable # 2 ha emitido su quinto elemento. El resultado utilizando zip
método zip
será el 3er valor emitido de ambos observables
.
En esta situación, el resultado utilizando combineLatest
será el 5º y 3º . Lo que se siente más natural.
combineLatest (observables)
De la documentation reactiveX:
Cada vez que cualquier entrada observable emite un valor, calcula una fórmula utilizando los últimos valores de todas las entradas y luego emite la salida de esa fórmula.
// 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 (observables)
El método Observable.zip se explica en la documentación de reactiveX :
Combina múltiples observables para crear un observable cuyos valores se calculan a partir de los valores, en orden, de cada uno de sus observables de entrada.
// 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();
})
una nota al margen (se aplica a ambos métodos)
El último parámetro, donde hemos proporcionado una función, (name: string, document: string) => ({name, document})
es opcional. Puedes omitirlo, o hacer operaciones más complejas:
Si el último parámetro es una función, esta función se utiliza para calcular el valor creado a partir de los valores de entrada. De lo contrario, se devuelve una matriz de los valores de entrada.
Entonces, si omites la última parte, obtienes una matriz:
// 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();
})
En mi aplicación tengo algo como:
this._personService.getName(id)
.concat(this._documentService.getDocument())
.subscribe((response) => {
console.log(response)
this.showForm()
});
//Output:
// [getnameResult]
// [getDocumentResult]
// I want:
// [getnameResult][getDocumentResult]
Luego obtengo dos resultados separados, primero el _personService
y luego el _documentService
. ¿Cómo puedo esperar los dos resultados antes de llamar a this.showForm()
para finalizar y luego manipular los resultados de cada uno?
Eche un vistazo al método ''combineLatest'', podría ser apropiado aquí. 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()
})
Para mí esta sample fue la mejor solución.
const source = Observable.interval(500);
const example = source.sample(Observable.interval(2000));
const subscribe = example.subscribe(val => console.log(''sample'', val));
Entonces ... solo cuando se emite el segundo (ejemplo): verá el último valor emitido del primero (fuente).
En mi tarea, espero la validación de formularios y otro evento DOM.
Puede usar ''zip'' o ''buffer'' como lo siguiente.
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}`));
Utilice el método forkJoin()
de observables. Compruebe este enlace para referencia
De los docs RXJS
Este operador se utiliza mejor cuando tiene un grupo de observables y solo se preocupa por el valor final emitido de cada uno. Un caso de uso común para esto es si desea emitir varias solicitudes en la carga de la página (o algún otro evento) y solo desea tomar medidas cuando se ha recibido una respuesta para todos. De esta manera, es similar a cómo puedes usar 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];
});
Código tomado de: https://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs