web-dev-qa-db-fra.com

Pourquoi avons-nous besoin d'utiliser flatMap?

Je commence à utiliser RxJS et je ne comprends pas pourquoi, dans cet exemple, nous devons utiliser une fonction comme flatMap ou concatAll; où est le tableau de tableaux ici?

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 quelqu'un peut expliquer visuellement ce qui se passe, ce sera très utile.

78
user233232

Quand j'ai commencé à regarder Rxjs j'ai aussi trébuché sur cette pierre. Ce qui m'a aidé est le suivant:

  • documentation de reactivex.io. Par exemple, pour flatMap: http://reactivex.io/documentation/operators/flatmap.html
  • documentation de rxmarbles: http://rxmarbles.com/ . Vous n'y trouverez pas flatMap, vous devez plutôt regarder mergeMap (un autre nom).
  • l'introduction à Rx qui vous manquait: https://Gist.github.com/staltz/868e7e9bc2a7b8c1f754 . Il aborde un exemple très similaire. En particulier, il traite du fait qu'une promesse s'apparente à un observable n'émettant qu'une seule valeur.
  • enfin en regardant les informations de type de RxJava. Javascript n'est pas dactylographié n'aide pas ici. Fondamentalement, si Observable<T> désigne un objet observable qui transmet des valeurs de type T, alors flatMap prend une fonction de type T' -> Observable<T> comme argument et renvoie Observable<T>. map prend une fonction de type T' -> T et renvoie Observable<T>.

    Pour revenir à votre exemple, vous avez une fonction qui produit des promesses à partir d’une chaîne d’URL. Donc, T' : string et T : promise. Et d'après ce que nous avons dit avant promise : Observable<T''>, donc T : Observable<T''>, avec T'' : html. Si vous mettez cette fonction de production de promesse dans map, vous obtenez Observable<Observable<T''>> lorsque ce que vous voulez est Observable<T''>: vous voulez que l'observable émette les valeurs html. flatMap s'appelle comme ça car elle aplatit (supprime un calque observable) le résultat de map. En fonction de vos antécédents, cela pourrait être chinois pour vous, mais tout est devenu clair pour moi avec les informations de frappe et le dessin d’ici: http://reactivex.io/documentation/operators/flatmap.html .

65
user3743222
['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]]

Vous utilisez flatMap lorsque vous avez un observable dont les résultats sont plus observables.

Si vous avez un observable qui est produit par un autre observable, vous ne pouvez pas le filtrer, le réduire ou le mapper directement car vous avez un observable, pas les données. Si vous produisez un observable, choisissez flatMap sur map; alors tu vas bien.

Comme dans le deuxième extrait, si vous effectuez une opération asynchrone, vous devez utiliser flatMap.

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>
105
serkan

flatMap transforme les éléments émis par un observable en nouveaux observables, puis aplatit les émissions de ceux-ci en un seul observable.

Découvrez le scénario ci-dessous où get("posts") renvoie un observable "aplati" par 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.
21
eosimosu

Les gens ont tendance à trop compliquer les choses en donnant la définition qui dit:

flatMap transforme les éléments émis par un observable en observables, puis les aplatit en un seul observable

Je jure que cette définition me trouble encore, mais je vais l'expliquer de la manière la plus simple, c'est-à-dire en utilisant un exemple.

Notre situation: nous avons un observable qui renvoie des données (une simple URL) que nous allons utiliser pour passer un appel HTTP qui renverra un observable contenant les données dont nous avons besoin afin que vous puissiez visualiser la situation de la sorte :

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

comme vous pouvez le constater, nous ne pouvons pas accéder directement aux données dont nous avons besoin. Le premier moyen de récupérer les données consiste à utiliser uniquement des abonnements normaux, comme ceci:

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

cela fonctionne, mais comme vous pouvez le constater, nous devons imbriquer des abonnements pour obtenir nos données. Pour le moment, cela n’a pas l’air mauvais, mais imaginons que nous ayons 10 abonnements imbriqués qui ne pourraient plus être maintenus.

une meilleure façon de gérer cela consiste donc simplement à utiliser l'opérateur flatMap qui fera la même chose mais nous évite cet abonnement imbriqué:

Observable_1
    .flatMap(URL => Http.get(URL))
    .subscribe(Data_We_Need => console.log(Data_We_Need));
18
Hamed Baatour

Ce n'est pas un tableau de tableaux. C'est un observable de observable (s).

Ce qui suit renvoie un flux observable de chaîne.

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

Bien que cela retourne un flux observable de flux observable de json

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

flatMap aplatit automatiquement l'observable pour que nous puissions observer directement le flux json

16
Lucius

Facile:

[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]]
14
drpicox

Un observable est un objet qui émet un flux d'événements: Next, Error et Completed.

Lorsque votre fonction renvoie un observable, il ne renvoie pas un flux, mais une instance de observable. L'opérateur flatMap mappe simplement cette instance sur un flux.

C'est le comportement de flatMap par rapport à map: Exécuter la fonction donnée et aplatir l'objet résultant dans un flux.

13
AkkarinZA

Ici pour montrer l'implémentation équivalente d'une flatMap en utilisant subscribe.

Sans flatMap:

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

Avec flatMap:

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

J'espère que ça pourrait aider.

Olivier.

7
olivier cherrier

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

Sans flatMap

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)})
})
5
Thanawat