Maison > interface Web > js tutoriel > Introduction à la programmation réactive fonctionnelle avec RXJS

Introduction à la programmation réactive fonctionnelle avec RXJS

Jennifer Aniston
Libérer: 2025-02-18 11:38:09
original
591 Les gens l'ont consulté

Introduction à la programmation réactive fonctionnelle avec RXJS

Les plats clés

  • La programmation réactive est une méthode de programmation avec des flux de données simultanés, qui peuvent être asynchrones. Il peut être appliqué aux problèmes de programmation car un processeur traite un flux d'informations composé d'instructions et de données.
  • La bibliothèque réactive pour la bibliothèque JavaScript (RXJS) utilise le chaînage de méthode et présente des observables (producteurs) et des observateurs (consommateurs). Les deux types d'observables sont des observables chauds, qui poussent même lorsqu'ils ne sont pas abonnés, et les observables à froid, qui commencent à pousser uniquement lorsqu'ils sont abonnés.
  • Les observables peuvent être créés à partir de tableaux, de promesses, de fonctions et de générateurs, et peuvent être utilisés pour fournir plusieurs valeurs de retour asynchrones. Les observables poussent les valeurs et ne peuvent pas forcer l'événement suivant.
  • RXJS fournit de nombreux opérateurs qui introduisent la concurrence, tels que l'accélérateur, l'intervalle ou le retard. Ceux-ci peuvent être utilisés pour agréger les événements sur un intervalle de temps spécifié, ou pour accélérer l'entrée pour démarrer uniquement les demandes après un certain temps d'inactivité.
  • RXJS rend la programmation réactive dans JavaScript plus facile et plus efficace. Il unifie certains des concepts de programmation réactive dans un ensemble de méthodes concises et composables. Il a également des extensions utiles, telles que RxJS-DOM, ce qui simplifie l'interaction avec le dom.

Cet article a été révisé par des pairs par Moritz Kröger, Bruno Mota et Vildan Softic. Merci à tous les pairs examinateurs de SitePoint pour avoir fait du contenu SitePoint le meilleur possible!

Avant de plonger dans le sujet, nous devons répondre à la question cruciale: qu'est-ce que la programmation réactive? À ce jour, la réponse la plus populaire est que la programmation réactive est la programmation avec des flux de données simultanés. La plupart du temps, nous trouverons le mot simultanément remplacé par des asynchrones, cependant, nous verrons plus tard que le flux n'a pas besoin d'être asynchrone.

Il est facile de voir que l'approche «tout est un flux» peut être appliquée directement à nos problèmes de programmation. Après tout, un CPU n'est rien de plus qu'un appareil qui traite un flux d'informations composé d'instructions et de données. Notre objectif est d'observer ce flux et de le transformer en cas de données particulières.

Les principes de la programmation réactive ne sont pas complètement nouveaux pour JavaScript. Nous avons déjà des choses comme la liaison des propriétés, le modèle EventEmitter ou les flux Node.js. Parfois, l'élégance de ces méthodes s'accompagne d'une diminution des performances, des abstractions trop compliquées ou des problèmes de débogage. Habituellement, ces inconvénients sont minimes par rapport aux avantages de la nouvelle couche d'abstraction. Nos exemples minimaux ne refléteront bien sûr pas l'application habituelle, mais seront aussi courtes et concises que possible.

Sans plus tarder, salissons nos mains en jouant avec la bibliothèque réactive des extensions pour JavaScript (RXJS). RXJS utilise beaucoup de choutage, qui est une technique populaire également utilisée dans d'autres bibliothèques telles que jQuery. Un guide du chaînage de méthodes (dans le contexte de Ruby) est disponible sur SitePoint.

Exemples de flux

Avant de plonger dans RXJS, nous devons énumérer quelques exemples pour travailler plus tard. Cela conclura également l'introduction à la programmation réactive et aux flux en général.

En général, nous pouvons distinguer deux types de flux: internes et externes. Alors que le premier peut être considéré comme artificiel et sous notre contrôle, les seconds proviennent de sources indépendantes de notre volonté. Les flux externes peuvent être déclenchés (directement ou indirectement) à partir de notre code.

Habituellement, les flux ne nous attendent pas. Ils se produisent, que nous puissions les gérer ou non. Par exemple, si nous voulons observer les voitures sur une route, nous ne pourrons pas redémarrer le flux de voitures. Le flux se déroule indépendamment de si nous l'observons ou non. Dans la terminologie RX, nous appelons cela un Hot observable . Rx introduit également observables à froid , qui se comportent plus comme des itérateurs standard, de sorte que les informations du flux se compose de tous les éléments pour chaque observateur.

Les images suivantes illustre certains types de flux externes. Nous voyons que les demandes (anciennement démarrées) et la configuration généralement des crochets Web sont mentionnées, ainsi que des événements d'interface utilisateur tels que les interactions de souris ou de clavier. Enfin, nous pouvons également recevoir des données de périphériques, par exemple des capteurs GPS, un accéléromètre ou d'autres capteurs.

Introduction à la programmation réactive fonctionnelle avec RXJS

L'image contenait également un flux noté comme messages . Les messages peuvent apparaître sous plusieurs formes. L'une des formes les plus simples est une communication entre notre site Web et un autre site Web. D'autres exemples incluent la communication avec les lignes Web ou les travailleurs du Web. Voyons un exemple de code pour ce dernier.

Le code du travailleur est présenté ci-dessous. Le code essaie de trouver les nombres premiers de 2 à 10 10 . Une fois un nombre trouvé, le résultat est rapporté.

<span>(function (start<span>, end</span>) {
</span>    <span>var n = start - 1;
</span>
    <span>while (n++ < end) {
</span>        <span>var k = Math.sqrt(n);
</span>        <span>var found = false;
</span>
        <span>for (var i = 2; !found && i <= k; ++i) {
</span>            found <span>= n % i === 0;
</span>        <span>}
</span>
        <span>if (!found) {
</span>            <span>postMessage(n.toString());
</span>        <span>}
</span>    <span>}
</span><span>})(2, 1e10);
</span>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Classiquement, le travailleur Web (supposé être dans le fichier prime.js) est inclus comme suit. Pour Brivity, nous ignorons les chèques pour le soutien des travailleurs Web et la légalité du résultat retourné.

<span>var worker = new Worker('prime.js');
</span>worker<span>.addEventListener('message', function (ev) {
</span>    <span>var primeNumber = ev.data * 1;
</span>    <span>console.log(primeNumber);
</span><span>}, false);
</span>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Plus de détails sur les travailleurs Web et le multi-threads avec JavaScript se trouvent dans l'article parallèle JavaScript avec parallel.js.

Compte tenu de l'exemple ci-dessus, nous savons que les nombres premiers suivent une distribution asymptotique entre les entiers positifs. Pour x à ∞, nous obtenons une distribution de x / log (x). Cela signifie que nous verrons plus de chiffres au début. Ici, les chèques sont également beaucoup moins chers (c'est-à-dire que nous recevons beaucoup plus de nombres premiers par unité de temps au début que plus tard.)

Cela peut être illustré avec un axe temporel simple et des blobs pour les résultats:

Introduction à la programmation réactive fonctionnelle avec RXJS

Un exemple non lié mais similaire peut être donné en examinant l'entrée d'un utilisateur dans une zone de recherche. Initialement, l'utilisateur peut être enthousiaste à la recherche de quelque chose à rechercher; Cependant, plus sa demande est spécifique, plus la différence de temps entre les traits clés devient grande. Fournir la possibilité de montrer des résultats en direct est certainement souhaitable, pour aider l'utilisateur à réduire sa demande. Cependant, ce que nous ne voulons pas, c'est effectuer une demande pour chaque accident vasculaire cérébral de clé, d'autant plus que les premiers seront effectués très rapidement et sans réfléchir ou la nécessité de se spécialiser.

Dans les deux scénarios, la réponse est d'agréger les événements précédents sur un intervalle de temps donné. Une différence entre les deux scénarios décrits est que les nombres premiers doivent toujours être affichés après l'intervalle de temps donné (c'est-à-dire que certains des nombres premiers sont tout simplement retardés dans la présentation). En revanche, la requête de recherche ne déclencherait une nouvelle demande que si aucune course de clé ne se produisait pendant l'intervalle spécifié. Par conséquent, la minuterie est réinitialisée une fois qu'un coup de clé a été détecté.

rxjs à la rescousse

RX est une bibliothèque pour composer des programmes asynchrones et basés sur des événements utilisant des collections observables. Il est bien connu pour sa syntaxe déclarative et sa composabilité tout en introduisant un modèle de gestion de temps et d'erreur facile. En pensant à nos anciens exemples, nous sommes particulièrement intéressés par la gestion du temps. Néanmoins, nous verrons qu'il y a beaucoup plus dans les RXJ pour bénéficier.

Les éléments constitutifs de base des RXJ sont des observables (producteurs) et des observateurs (consommateurs). Nous avons déjà mentionné les deux types d'observables:

  • Les observables chauds poussent même lorsque nous ne les sommes pas abonnés (par exemple, les événements d'interface utilisateur).
  • Les observables froids commencent à pousser uniquement lorsque nous souscrivons. Ils recommencent si nous abons à nouveau.

Les observables à froid se réfèrent généralement à des tableaux ou à des valeurs uniques qui ont été converties pour être utilisées dans RXJS. Par exemple, le code suivant crée un froid observable qui ne donne qu'une seule valeur avant de terminer:

<span>(function (start<span>, end</span>) {
</span>    <span>var n = start - 1;
</span>
    <span>while (n++ < end) {
</span>        <span>var k = Math.sqrt(n);
</span>        <span>var found = false;
</span>
        <span>for (var i = 2; !found && i <= k; ++i) {
</span>            found <span>= n % i === 0;
</span>        <span>}
</span>
        <span>if (!found) {
</span>            <span>postMessage(n.toString());
</span>        <span>}
</span>    <span>}
</span><span>})(2, 1e10);
</span>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Nous pouvons également renvoyer une fonction contenant une logique de nettoyage à partir de la fonction de création observable.

L'abonnement à l'observable est indépendant du type d'observable. Pour les deux types, nous pouvons fournir trois fonctions qui remplissent l'exigence de base de la grammaire de notification composée de OnNext, ONERROR et ONCOMPLETED. Le rappel OnNext est obligatoire.

<span>var worker = new Worker('prime.js');
</span>worker<span>.addEventListener('message', function (ev) {
</span>    <span>var primeNumber = ev.data * 1;
</span>    <span>console.log(primeNumber);
</span><span>}, false);
</span>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

En tant que meilleure pratique, nous devons mettre fin à l'abonnement en utilisant la méthode Disser. Cela effectuera toutes les étapes de nettoyage requises. Sinon, il pourrait être possible d'empêcher la collecte des ordures de nettoyer les ressources inutilisées.

sans souscrire, l'observable contenu dans la variable observable est juste un froid observable. Néanmoins, il est également possible de le convertir en une séquence chaude (c'est-à-dire que nous effectuons un abonnement pseudo) en utilisant la méthode de publication.

<span>(function (start<span>, end</span>) {
</span>    <span>var n = start - 1;
</span>
    <span>while (n++ < end) {
</span>        <span>var k = Math.sqrt(n);
</span>        <span>var found = false;
</span>
        <span>for (var i = 2; !found && i <= k; ++i) {
</span>            found <span>= n % i === 0;
</span>        <span>}
</span>
        <span>if (!found) {
</span>            <span>postMessage(n.toString());
</span>        <span>}
</span>    <span>}
</span><span>})(2, 1e10);
</span>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Certains des aides contenus dans les RXJ ne traitent que la conversion des structures de données existantes. En JavaScript, nous pouvons distinguer trois d'entre eux:

  1. promet de retourner des résultats asynchrones uniques,
  2. Fonctions pour les résultats uniques, et
  3. générateurs pour fournir des itérateurs.

Ce dernier est nouveau avec ES6 et peut être remplacé par des tableaux (même si c'est un mauvais substitut et doit être traité comme une seule valeur) par ES5 ou plus.

RXJS apporte désormais un type de données pour fournir la prise en charge de la valeur multiple (retour) asynchrone. Par conséquent, les quatre quadrants sont maintenant remplis.

Introduction à la programmation réactive fonctionnelle avec RXJS

Alors que les itérateurs doivent être tirés, les valeurs des observables sont poussées. Un exemple serait un flux d'événements, où nous ne pouvons pas forcer le prochain événement à se produire. Nous ne pouvons attendre que d'être averti par la boucle d'événement.

<span>var worker = new Worker('prime.js');
</span>worker<span>.addEventListener('message', function (ev) {
</span>    <span>var primeNumber = ev.data * 1;
</span>    <span>console.log(primeNumber);
</span><span>}, false);
</span>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

La plupart des aides créant ou traitant des observables acceptent également un planificateur, qui contrôle le début d'un abonnement et lorsque les notifications sont publiées. Nous n'entrerons pas dans les détails ici car le planificateur par défaut fonctionne très bien à la plupart des fins pratiques.

De nombreux opérateurs dans les RXJ introduisent la concurrence, tels que l'accélérateur, l'intervalle ou le retard. Nous allons maintenant examiner les exemples précédents, où ces aides deviennent essentiels.

Exemples

Tout d'abord, jetons un coup d'œil à notre générateur de nombres premiers. Nous voulions agréger les résultats au cours d'un temps donné, de sorte que l'interface utilisateur (en particulier au début) n'a pas à faire face à trop de mises à jour.

Ici, nous pourrions en fait vouloir utiliser la fonction tampon de RXJS en conjonction avec l'assistant d'intervalle mentionné précédemment.

Le résultat doit être représenté par le diagramme suivant. Les blobs verts surviennent après un intervalle de temps spécifié (donné par le temps utilisé pour construire l'intervalle). Un tampon agrégera tous les blobs bleus vus pendant un tel intervalle.

Introduction à la programmation réactive fonctionnelle avec RXJS

De plus, nous pourrions également introduire la carte, ce qui nous aide à transformer les données. Par exemple, nous pouvons vouloir transformer les arguments d'événement reçus pour obtenir les données transmises en nombre.

<span>var observable = Rx.<span>Observable</span>.create(function (observer) {
</span>  observer<span>.onNext(42);
</span>  observer<span>.onCompleted();
</span><span>});
</span>
Copier après la connexion

La fonction Fromevent construit un observable à partir de tout objet utilisant le modèle d'émetteur d'événement standard. Le tampon renverrait également des tableaux avec une longueur zéro, c'est pourquoi nous introduisons la fonction où réduire le flux en tableaux non vides. Enfin, dans cet exemple, nous ne sommes intéressés que par le nombre de nombres premiers générés. Par conséquent, nous mapperons le tampon pour obtenir sa longueur.

L'autre exemple est la zone de requête de recherche, qui doit être étranglée pour démarrer les demandes qu'après un certain temps inactive. Il existe deux fonctions qui peuvent être utiles dans un tel scénario: la fonction de gaz donne la première entrée vue dans une fenêtre de temps spécifiée. La fonction de débouchement donne la dernière entrée vue dans une fenêtre de temps spécifiée. Les fenêtres temporelles sont également décalées en conséquence (c'est-à-dire par rapport au premier / dernier élément).

Nous voulons réaliser un comportement qui se reflète par le diagramme suivant. Par conséquent, nous allons utiliser le mécanisme de débouchement.

Introduction à la programmation réactive fonctionnelle avec RXJS

Nous voulons jeter tous les résultats précédents et obtenir le dernier avant la fenêtre de l'heure épuisée. En supposant que le champ de saisie a la requête ID, nous pourrions utiliser le code suivant:

<span>(function (start<span>, end</span>) {
</span>    <span>var n = start - 1;
</span>
    <span>while (n++ < end) {
</span>        <span>var k = Math.sqrt(n);
</span>        <span>var found = false;
</span>
        <span>for (var i = 2; !found && i <= k; ++i) {
</span>            found <span>= n % i === 0;
</span>        <span>}
</span>
        <span>if (!found) {
</span>            <span>postMessage(n.toString());
</span>        <span>}
</span>    <span>}
</span><span>})(2, 1e10);
</span>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans ce code, la fenêtre est définie sur 300 ms. Nous limitons également les requêtes pour les valeurs avec au moins 3 caractères, qui sont distinctes des requêtes précédentes. Cela élimine les demandes inutiles d'entrées qui viennent d'être corrigées en tapant quelque chose et en l'effacement.

Il y a deux parties cruciales dans toute cette expression. L'un est la transformation du texte de requête en une demande utilisant la recherche, l'autre est la fonction Switch (). Ce dernier prend toute fonction qui renvoie des observables imbriqués et produit des valeurs uniquement à partir de la séquence observable la plus récente.

La fonction pour créer les demandes pourrait être définie comme suit:

<span>var worker = new Worker('prime.js');
</span>worker<span>.addEventListener('message', function (ev) {
</span>    <span>var primeNumber = ev.data * 1;
</span>    <span>console.log(primeNumber);
</span><span>}, false);
</span>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Notez l'observable imbriqué (qui peut entraîner des demandes non définies pour les demandes non valides), c'est pourquoi nous chouchons Switch () et où ().

Conclusions

RXJS fait de la programmation réactive en Javascript une réalité joyeuse. En tant qu'alternative, il y a aussi Bacon.js, qui fonctionne de manière similaire. Néanmoins, l'une des meilleures choses à propos de RXJS est Rx lui-même, qui est disponible sur de nombreuses plateformes. Cela rend la transition vers d'autres langues, plates-formes ou systèmes assez faciles. Il unifie également certains des concepts de programmation réactive dans un ensemble de méthodes concises et composables. En outre, plusieurs extensions très utiles existent, telles que RXJS-DOM, ce qui simplifie l'interaction avec le dom.

où voyez-vous briller Rxjs?

Des questions fréquemment posées sur la programmation réactive fonctionnelle avec RXJS

Quelle est la différence entre la programmation fonctionnelle et la programmation réactive fonctionnelle?

La programmation fonctionnelle (FP) et la programmation réactive fonctionnelle (FRP) sont toutes deux des paradigmes de programmation, mais ils ont des foyer différents. FP est un style de programmation qui traite le calcul comme l'évaluation des fonctions mathématiques et évite les données changeantes et mutables. Il met l'accent sur l'application des fonctions, contrairement au style de programmation impératif, qui met l'accent sur les changements d'état.

En revanche, le FRP est une variante de FP qui traite des flux de données asynchrones. Il combine le modèle de programmation réactive avec une programmation fonctionnelle. En FRP, vous pouvez exprimer des flux de données statiques (par exemple, tableaux) et dynamiques (par exemple, clics de souris, demandes Web) et réagir à leurs modifications.

Comment les RXJ s'intègrent-ils dans la programmation réactive fonctionnelle?

RXJS (extensions réactives pour JavaScript) est une bibliothèque de programmation réactive à l'aide d'observables, pour faciliter la composition du code asynchrone ou basé sur un rappel. Cela en fait un ajustement parfait pour la programmation réactive fonctionnelle. Avec les RXJ, vous pouvez créer des flux de données à partir de diverses sources et également transformer, combiner, manipuler ou réagir à ces flux de données à l'aide de ses opérateurs fournis.

Que sont les observables dans les RXJS?

Les observables sont des observables sont Un concept de base dans RXJS. Ce sont des flux de données, ce qui peut émettre plusieurs valeurs au fil du temps. Ils peuvent émettre trois types de valeurs: suivant, erreur et terminer. Les valeurs «suivantes» peuvent être n'importe quel objet JavaScript, «Error» est un objet d'erreur lorsque quelque chose ne va pas, et «complet» n'a pas de valeur, il signale simplement que l'observable n'émettra pas plus de valeurs.

Comment gérer les erreurs dans RXJS?

RXJS fournit plusieurs opérateurs pour gérer les erreurs, telles que Catcherror et Retry. L'opérateur Catcherror attrape l'erreur sur la source observable et continue le flux avec un nouveau observable ou une erreur. L'opérateur de réessayer remonte à la source observable lorsqu'il échoue.

Que sont les opérateurs dans RXJS?

Les opérateurs sont des fonctions pures qui permettent un puissant style de programmation fonctionnelle pour gérer les collections avec des opérations comme «MAP» «,« filtre »,« concat »,« réduction », etc. Il existe des dizaines d'opérateurs disponibles dans les RXJ qui peuvent être utilisés pour gérer des manipulations complexes de collections, qu'il s'agisse de réseaux d'articles, de flux d'événements ou même de promesses.

Comment puis-je tester mon code RXJS?

RXJS fournit des utilitaires de test, tels que TestScheduler, qui facilite le test asynchrone. Vous pouvez également utiliser des diagrammes de marbre pour visualiser les observables pendant les tests.

Puis-je utiliser des RXJ avec Angular?

Oui, RXJS est en fait un élément clé d'Angular. Il est utilisé dans le module HTTP d'Angular et également dans la classe EventEmitter qui est utilisé pour des événements personnalisés.

Quelle est la différence entre les promesses et les observables?

Les promesses et les observables traitent tous les deux des opérations asynchrones, mais elles le font de différentes manières. Une promesse est une valeur qui peut ne pas encore être disponible. Il ne peut être résolu (rempli ou rejeté) qu'une seule fois. D'un autre côté, un observable est un flux de valeurs qui peut émettre zéro ou plus de valeurs, et il peut être abonné ou non publié.

Comment puis-je me désinscrire d'un?

Lorsque vous vous abonnez à un observable, vous obtenez un objet d'abonnement. Vous pouvez appeler la méthode de désabonnement sur cet objet pour annuler l'abonnement et arrêter de recevoir des données.

Quels sont les sujets dans RXJS?

Les sujets en RXJ sont un type spécial d'observable qui permet multidiffusion à de nombreux observateurs. Contrairement aux observables simples, les sujets maintiennent un registre de nombreux auditeurs.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal