javascript - ejemplo - rxjs angular



Cómo 'esperar' por dos observables en RxJS (4)

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?


Answer #1

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

Answer #2

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

Answer #3

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

Answer #4

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





reactive-programming