181 votes

A quoi sert le tuyau dans RxJS ?

Je pense que j'ai le concept de base, mais il y a quelques obscurités.

En général, c'est ainsi que j'utilise un Observable :

observable.subscribe(x => {

})

Si je veux filtrer les données, je peux utiliser ceci :

import { first, last, map, reduce, find, skipWhile } from 'rxjs/operators';
observable.pipe(
    map(x => {return x}),
    first()
    ).subscribe(x => {

})

Je peux aussi le faire :

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/first';

observable.map(x => {return x}).first().subscribe(x => {

})

Mes questions sont donc les suivantes :

  1. Quelle est la différence ?
  2. S'il n'y a pas de différence, pourquoi la fonction pipe existe ?
  3. Pourquoi ces fonctions ont-elles besoin d'importations différentes ?

1 votes

J'allais dire que c'est pour les opérateurs personnalisés, non natifs, mais je ne sais même pas si c'est exact. Est-ce que pipe() vous permet de passer les opérateurs que vous créez ?

105voto

Martin Points 1093

Les opérateurs " canalisables " (anciennement " louables ") sont la méthode actuelle et recommandée d'utiliser des opérateurs depuis RxJS 5.5.

Je vous recommande vivement de lire le documentation officielle sur les exploitants de canalisations

La principale différence est qu'il est plus facile de faire des opérateurs personnalisés et qu'il est plus facile de faire des arbres tout en n'altérant pas certains éléments globaux. Observable qui pourrait éventuellement provoquer des collisions si deux parties différentes voulaient créer un opérateur du même nom.

En utilisant des import pour chaque opérateur 'rxjs/add/operator/first' était un moyen de faire des paquets d'applications plus petits. En important uniquement les opérateurs dont vous avez besoin au lieu de toute la bibliothèque RxJS, vous pouvez réduire considérablement la taille totale du paquet. Cependant, le compilateur ne peut pas savoir si vous avez importé 'rxjs/add/operator/first' parce que vous en avez vraiment besoin dans votre code ou que vous avez simplement oublié de le supprimer lors du remaniement de votre code. C'est l'un des avantages de l'utilisation d'opérateurs pipeables où les importations inutilisées sont automatiquement ignorées.

2 votes

A propos de votre affirmation unused imports are ignored automatically Actuellement, les IDE disposent de plugins qui suppriment les importations inutilisées.

2 votes

Tout le monde n'utilise pas ces IDE ou ces plugins, beaucoup de gens utilisent un éditeur de texte de base. La plupart du temps, nous ne pouvons pas affirmer que tous les membres de l'équipe utilisent le même IDE, le même ensemble de plugins ou le même éditeur de texte que nous.

5 votes

@AdamFaryna Bien sûr, certaines équipes peuvent aussi écrire du code sur papier, mais pourquoi le feraient-elles si elles disposent d'outils modernes ? L'utilisation d'un éditeur de texte, en particulier sans les plugins importants, est similaire à l'écriture de code sur papier. Vous pouvez le faire, mais pourquoi une équipe/développeur décent le ferait-il ?

26voto

ORBIT Points 1

La méthode du tuyau

Selon la documentation originale

l'opérateur pipable est que fonction prendre les observables comme entrée et il retourne un autre observable .l'observable précédent reste inchangé.

pipe(...fns: UnaryFunction<any, any>[]): UnaryFunction<any, any>

Poste original

Que veut dire tuyau ?

Cela signifie que tous les opérateurs que vous avez précédemment utilisés sur l'instance de observable sont disponibles en tant que fonctions pures sous rxjs/operators . Ainsi, construire une composition d'opérateurs ou réutiliser des opérateurs devient vraiment facile, sans avoir à recourir à toutes sortes de gymnastique de programmation où vous devez créer un observable personnalisé qui étend l'Observable, puis écraser l'ascenseur juste pour faire votre propre chose personnalisée. personnalisé.

const { Observable } = require('rxjs/Rx')
const { filter, map, reduce,  } = require('rxjs/operators')
const { pipe } = require('rxjs/Rx')

const filterOutWithEvens = filter(x => x % 2)
const doubleByValue = x => map(value => value * x);
const sumValue = reduce((acc, next) => acc + next, 0);
const source$ = Observable.range(0, 10)

source$.pipe(
  filterOutWithEvens, 
  doubleByValue(2), 
  sumValue)
  .subscribe(console.log); // 50

0 votes

@VladKuts changer les codes et les attributs donnés .désolé pour le dérangement.

1 votes

Merci, je n'avais même pas réalisé que je pouvais stocker des opérateurs pouvant être utilisés comme références de fonctions et les utiliser dans l'appel pipe(). C'est beaucoup plus propre que de toujours le faire en ligne.

21voto

Don Dilanga Points 589

Quelle est la différence ? Comme vous le voyez dans votre exemple, la principale différence consiste à améliorer la lisibilité du code source. Il n'y a que deux fonctions dans votre exemple, mais imaginez qu'il y en ait une douzaine ? alors cela donnera

function1().function2().function3().function4()

ça devient vraiment moche et difficile à lire, surtout quand on remplit l'intérieur des fonctions. En plus de cela, certains éditeurs, comme Visual Studio code, ne permettent pas de dépasser 140 lignes.

Observable.pipe(
function1(),
function2(),
function3(),
function4()
)

Cela améliore considérablement la lisibilité.

S'il n'y a pas de différence, pourquoi le tuyau de fonction existe-t-il ? Le but de la fonction PIPE() est de regrouper toutes les fonctions qui prennent, et retournent l'observable. Elle prend une observable au départ, puis cette observable est utilisée tout au long de la fonction pipe() par chaque fonction utilisée à l'intérieur de celle-ci.

La première fonction prend l'observable, le traite, modifie sa valeur et le passe à la fonction suivante, puis la fonction suivante prend l'observable de sortie de la première fonction, le traite et le passe à la fonction suivante, et ainsi de suite jusqu'à ce que toutes les fonctions à l'intérieur de la fonction pipe() utilisent cet observable, et enfin vous avez l'observable traité. À la fin, vous pouvez exécuter l'observable avec la fonction subscribe() pour en extraire la valeur. N'oubliez pas que les valeurs de l'observable d'origine ne sont pas modifiées ! 

Pourquoi ces fonctions ont-elles besoin d'importations différentes ? Les importations dépendent de l'endroit où la fonction est spécifiée dans le paquet rxjs. Cela se passe comme suit. Tous les modules sont stockés dans le dossier node_modules dans Angular. import { class } from "module" ;

Prenons le code suivant comme exemple. Je viens de l'écrire dans stackblitz. Rien n'est donc généré automatiquement, ni copié depuis un autre endroit. Je ne vois pas l'intérêt de copier ce qui est indiqué dans la documentation rxjs quand on peut aller la lire aussi. Je suppose que vous avez posé cette question ici, parce que vous n'avez pas compris la documentation. 

  • Il existe des classes pipe, observable, of, map importées depuis les modules respectifs. 

  • Dans le corps de la classe, j'ai utilisé la fonction Pipe() comme on le voit dans le code. 

  • La fonction Of() renvoie un observable, à savoir émet des nombres en séquence lorsqu'elle est souscrite.

  • Observable n'est pas encore inscrit.

  • Lorsque vous l'utilisez comme Observable.pipe(), la fonction pipe() utilise l'Observable donné comme entrée.

  • La première fonction, la fonction map(), utilise cet Observable, le traite et renvoie l'Observable traité à la fonction pipe(),

  • alors cet Observable traité est donné à la fonction suivante s'il y en a une,

  • et cela continue ainsi jusqu'à ce que toutes les fonctions traitent l'Observable,

  • à la fin, cet Observable est retourné par la fonction pipe() vers une variable, dans l'exemple suivant son obs.

Maintenant, le truc avec l'Observable, c'est que tant que l'observateur n'y a pas souscrit, il n'émet aucune valeur. Donc j'ai utilisé la fonction subscribe() pour souscrire à cet Observable, puis dès que je l'ai souscrit. La fonction of() commence à émettre des valeurs, puis elles sont traitées par la fonction pipe(), et vous obtenez le résultat final à la fin, par exemple 1 est pris de la fonction of(), 1 est ajouté 1 dans la fonction map(), et renvoyé. Vous pouvez obtenir cette valeur comme argument à l'intérieur de la fonction subscribe() ( argument ) {} ) fonction.

Si vous voulez l'imprimer, alors utilisez comme

subscribe( function (argument) {
    console.log(argument)
   } 
)

    import { Component, OnInit } from '@angular/core';
    import { pipe } from 'rxjs';
    import { Observable, of } from 'rxjs';
    import { map } from 'rxjs/operators';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent implements OnInit  {
    
      obs = of(1,2,3).pipe(
      map(x => x + 1),
      ); 
    
      constructor() { }
    
      ngOnInit(){  
        this.obs.subscribe(value => console.log(value))
      }
    }

https://stackblitz.com/edit/angular-ivy-plifkg

15voto

Juan Mendes Points 31678

Un bon résumé que j'ai trouvé est :

Il découple les opérations de streaming (map, filter, reduce...) de la fonctionnalité principale (souscription, piping). En canalisant les opérations au lieu de les enchaîner, il ne pollue pas le prototype de l'Observable, ce qui facilite le secouage de l'arbre.

Voir https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md#why

Les problèmes avec les opérateurs corrigés pour le chaînage par points sont les suivants :

Toute bibliothèque qui importe un opérateur de correctif augmentera la valeur de l'opérateur de correctif. Observable.prototype pour tous les consommateurs de cette bibliothèque, créant ainsi des dépendances aveugles. Si la bibliothèque supprime leur utilisation, ils brisent sans le savoir tous les autres. briser tous les autres. Avec les pipelines, vous devez importer les opérateurs dont vous avez besoin dans chaque fichier où vous les utilisez.

Les opérateurs patchés directement sur le prototype ne sont pas "tree-shakeable". par des outils comme rollup ou webpack. Les opérateurs "pipeables" le seront puisqu'ils car ils ne sont que des fonctions tirées directement des modules.

Les opérateurs inutilisés qui sont importés dans les applications ne peuvent pas être détectés de manière fiable par aucune sorte d'outil de construction ou de règle de lint. Cela signifie que vous pouvez importer un scan, mais arrêter de l'utiliser, et il est quand même ajouté à votre bundle de sortie. Avec les opérateurs pipeables, si vous n'utilisez pas une règle lint peut le récupérer pour vous.

La composition fonctionnelle est impressionnante. Construire vos propres opérateurs personnalisés personnalisés devient beaucoup, beaucoup plus facile, et maintenant ils fonctionnent et ressemblent à tous les autres opérateurs de rxjs. Vous n'avez pas besoin d'étendre Observable ou de de surcharger l'ascenseur.

7voto

Yilmaz Points 51

C'est ainsi que j'explique l'observable :

Vous devez établir un plan en fonction des conditions météorologiques. Vous allumez donc une radio et écoutez une chaîne météo qui diffuse les conditions météorologiques 24 heures sur 24 et 7 jours sur 7. Dans ce scénario, au lieu d'obtenir une réponse unique, la réponse est continue. Cette réponse est comme un abonnement à un observable. L'observable est la "météo" et l'abonnement est les "signaux radio qui vous tiennent au courant". Tant que votre radio est allumée, vous recevez toutes les mises à jour disponibles. Vous ne manquez aucune information jusqu'à ce que vous éteigniez la radio.

J'ai dit que la météo est observable, mais vous écoutez la radio, pas la météo. Donc la radio est aussi un observable. Ce que dit le présentateur météo est la fonction du bulletin météo que lui envoie le météorologue. Ce que le météorologue écrit est fonction des données provenant de la station météo. Les données provenant de la station météorologique sont fonction de tous les instruments (baromètre, girouette, anémomètre) qui y sont fixés et les instruments sont fonction du temps lui-même.

Il y a au moins 5 observables dans tout ce processus. Dans ce processus, il y a deux types d'observables. L'observable de la source et l'observable de la sortie. Dans cet exemple, la météo est l'"observable source" et la radio est l'"observable de sortie". Tout ce qui se trouve entre les deux représente le PIPE FUNCTION .

Fonction du tuyau est ce qui prend l'observable source et effectue des opérations dessus pour fournir un observable de sortie et toutes ces opérations se passent à l'intérieur. Les opérations portent toutes sur les observables elles-mêmes

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X