¿Por qué necesitamos usar flatMap?


Estoy empezando a usar RxJS y no entiendo por qué en este ejemplo necesitamos usar una función como flatMap o concatAll; ¿dónde está la matriz de matrices aquí?

var requestStream = Rx.Observable.just('https://api.github.com/users');

var responseMetastream = requestStream
  .flatMap(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseMetastream.subscribe(url => {console.log(url)})

Si alguien puede explicar visualmente lo que está sucediendo, será muy útil.

Author: msanford, 2015-11-02

9 answers

Cuando empecé a echar un vistazo a Rxjs también tropecé con esa piedra. Lo que me ayudó es lo siguiente:

  • documentación de reactivex.io . Por ejemplo, para flatMap: http://reactivex.io/documentation/operators/flatmap.html
  • documentación de rxmarbles: http://rxmarbles.com / . No encontrarás flatMap allí, debes mirar mergeMap en su lugar (otro nombre).
  • la introducción a Rx que te has estado perdiendo : https://gist.github.com/staltz/868e7e9bc2a7b8c1f754 . Aborda un ejemplo muy similar. En particular, aborda el hecho de que una promesa es similar a un observable que emite un solo valor.
  • Finalmente mirando la información de tipo de RxJava. Javascript no ser escrito no ayuda aquí. Básicamente si Observable<T> denota un objeto observable que empuja valores de tipo T, entonces flatMap toma una función de tipo T' -> Observable<T> como su argumento, y devuelve Observable<T>. map toma una función de tipo T' -> T y devuelve Observable<T>.

    Volviendo a tu ejemplo, tienes una función que produce promesas a partir de una cadena url. Así que T' : string, y T : promise. Y de lo que dijimos antes promise : Observable<T''>, así T : Observable<T''>, con T'' : html. si pones esa función promise producing en map, obtienes Observable<Observable<T''>> cuando lo que quieres es Observable<T''>: quieres que el observable emita los valores html. flatMap se llama así porque aplana (elimina una capa observable) el resultado de map. Dependiendo de su antecedentes, esto podría ser chino para usted, pero todo se volvió claro para mí con la información de escritura y el dibujo de aquí : http://reactivex.io/documentation/operators/flatmap.html.

 53
Author: user3743222,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-22 04:19:41
['a','b','c'].flatMap(function(e) {
    return [e, e+ 'x', e+ 'y',  e+ 'z'  ];
});
//['a', 'ax', 'ay', 'az', 'b', 'bx', 'by', 'bz', 'c', 'cx', 'cy', 'cz']


['a','b','c'].map(function(e) {
    return [e, e+ 'x', e+ 'y',  e+ 'z'  ];
});
//[Array[4], Array[4], Array[4]]

Se usa flatMap cuando se tiene un Observable cuyos resultados son más Observables.

Si tiene un observable que es producido por otro observable, no puede filtrarlo, reducirlo o mapearlo directamente porque tiene un Observable no los datos. Si produce un observable, elija flatMap sobre map; entonces está bien.

Al igual que en el segundo fragmento, si está haciendo una operación asincrónica, debe usar Mapa plano.

var source = Rx.Observable.interval(100).take(10).map(function(num){
    return num+1
});
source.subscribe(function(e){
    console.log(e)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.1/Rx.min.js"></script>

var source = Rx.Observable.interval(100).take(10).flatMap(function(num){
    return Rx.Observable.timer(100).map(() => num)
});
source.subscribe(function(e){
    console.log(e)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.1/Rx.min.js"></script>
 89
Author: serkan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-20 00:45:48

flatMap transformar los elementos emitidos por un Observable en nuevos Observables, luego aplana las emisiones de esos en un solo Observable.

Echa un vistazo al siguiente escenario donde get("posts") devuelve un Observable que está "aplanado" por flatMap.

myObservable.map(e => get("posts")).subscribe(o => console.log(o));
// this would log Observable objects to console.  

myObservable.flatMap(e => get("posts")).subscribe(o => console.log(o));
// this would log posts to console.
 18
Author: eosimosu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-04 02:00:42

No es una matriz de matrices. Es un observable de observable (s).

Lo siguiente devuelve un flujo observable de cadena.

requestStream
  .map(function(requestUrl) {
    return requestUrl;
  });

Mientras que esto devuelve un flujo observable de flujo observable de json

requestStream
  .map(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

flatMap aplana el observable automáticamente para nosotros para que podamos observar el flujo json directamente

 15
Author: Lucius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-08 09:51:25

Un Observable es un objeto que emite una secuencia de eventos: Siguiente, Error y Completado.

Cuando su función devuelve un Observable, no devuelve un flujo, sino una instancia de Observable. El operador flatMap simplemente asigna esa instancia a una secuencia.

Ese es el comportamiento de flatMap cuando se compara con map: Ejecuta la función dada y aplana el objeto resultante en una secuencia.

 10
Author: AkkarinZA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-02 07:51:11

Simple:

[1,2,3].map(x => [x, x * 10])
// [[1, 10], [2, 20], [3, 30]]

[1,2,3].flatMap(x => [x, x * 10])
// [1, 10, 2, 20, 3, 30]]
 10
Author: drpicox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-31 23:05:27

La gente tiende a complicar las cosas dando la definición que dice:

FlatMap transforma los elementos emitidos por un Observable en Observables, a continuación, aplanar las emisiones de los mismos en un solo Observable

Juro que esta definición todavía me confunde, pero voy a explicarla de la manera más simple, que es usando un ejemplo

Nuestra situación : tenemos un observable que devuelve datos (URL simple) que vamos a úselo para hacer una llamada HTTP que devolverá un observable que contenga los datos que necesitamos para que pueda visualizar la situación de esta manera:

Observable 1
    |_
       Make Http Call Using Observable 1 Data (returns Observable_2)
            |_
               The Data We Need

Así que como se puede ver no podemos llegar a los datos que necesitamos directamente por lo que la primera forma de recuperar los datos que podemos utilizar sólo suscripciones normales como esta:

Observable_1.subscribe((URL) => {
         Http.get(URL).subscribe((Data_We_Need) => {
                  console.log(Data_We_Need);
          });
});

Esto funciona, pero como puede ver, tenemos que anidar suscripciones para obtener nuestros datos. esto actualmente no se ve mal, pero imagine que tenemos 10 suscripciones anidadas que se convertirían en inalcanzable.

Así que una mejor manera de manejar esto es usar el operador flatMap que hará lo mismo pero nos hace evitar esa suscripción anidada:

Observable_1
    .flatMap(URL => Http.get(URL))
    .subscribe(Data_We_Need => console.log(Data_We_Need));
 8
Author: Hamed Baatour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-28 18:11:06

Con flatMap

var requestStream = Rx.Observable.just('https://api.github.com/users');

var responseMetastream = requestStream
  .flatMap(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseMetastream.subscribe(json => {console.log(json)})

Sin Mapa plano

var requestStream = Rx.Observable.just('https://api.github.com/users');

var responseMetastream = requestStream
  .map(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseMetastream.subscribe(jsonStream => {
  jsonStream.subscribe(json => {console.log(json)})
})
 3
Author: Thanawat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-18 11:14:33

Aquí para mostrar la implementación equivalente de un mapa plano utilizando subscribes.

Sin Mapa plano:

this.searchField.valueChanges.debounceTime(400)
.subscribe(
  term => this.searchService.search(term)
  .subscribe( results => {
      console.log(results);  
      this.result = results;
    }
  );
);

Con Mapa plano:

this.searchField.valueChanges.debounceTime(400)
    .flatMap(term => this.searchService.search(term))
    .subscribe(results => {
      console.log(results);
      this.result = results;
    });

Http://plnkr.co/edit/BHGmEcdS5eQGX703eRRE?p=preview

Espero que pueda ayudar.

Olivier.
 3
Author: olivier cherrier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-11 13:06:22