64 votes

Les événements vs Flux vs Observables vs Asynchrone Itérateurs

Actuellement, la seule manière stable à traiter une série de async résultats en JavaScript en utilisant le système d'événements. Cependant, trois alternatives sont en cours d'élaboration:

Flux: https://streams.spec.whatwg.org
Observables: https://tc39.github.io/proposal-observable
Async Itérateurs: https://tc39.github.io/proposal-async-iteration

Quelles sont les différences et les avantages de chacun sur les événements et les autres?

De l'intention de remplacer les événements?

153voto

Domenic Points 40761

Il y a environ deux catégories d'Api ici: tirer et pousser.

Pull

Async pull Api sont un bon ajustement pour les cas où les données sont extraites à partir d'une source. Cette source peut être un fichier, ou une socket réseau, ou une liste de répertoires, ou quoi que ce soit d'autre. L'essentiel est que le travail est fait de tirer ou de produire des données à partir de la source lorsque demandé.

Async les itérateurs sont la base primitive ici, censé être un générique de manifestation de la notion de pull async source. Dans une telle source, vous:

  • Tirer à partir d'un async itérateur en faisant const promise = ai.next()
  • Attendre le résultat de l'utilisation d' const result = await promise (ou à l'aide de .then())
  • Inspecter le résultat pour savoir si c'est une exception (jeté), une valeur intermédiaire ({ value, done: false }), ou un fait de signal ({ value: undefined, done: true }).

Ceci est similaire à la façon de synchroniser les itérateurs sont une générique manifestation de la notion de traction en fonction de synchronisation source de valeur. Les étapes pour une synchronisation itérateur sont exactement les mêmes que ci-dessus, en omettant les "attendre le résultat de l'étape.

Lisible, les ruisseaux sont un cas particulier de la async itérateurs, visent expressément à encapsuler les I/O de sources comme les sockets/fichiers/etc. Ils se sont spécialisés, des Api pour la tuyauterie à inscriptible flux (représentant l'autre moitié de l'I/O de l'écosystème, éviers) et la manipulation de l'résultant de contre-pression. Ils peuvent également être spécialisé pour manipuler des octets dans un efficace "apportez votre propre tampon" de manière. C'est tout ce qui rappelle quelque peu de la façon dont les tableaux sont un cas particulier de la synchronisation des itérateurs, optimisé pour O(1) un accès indexé.

Une autre caractéristique de l'ouverture des Api, c'est qu'ils sont généralement de simple consommateur. Celui qui tire la valeur, maintenant qu'il est, et il n'existe pas dans la source asynchrone itérateur/stream/etc. plus. Il a été retiré par le consommateur.

En général, pull Api fournissent une interface pour la communication avec certains sous-jacente source de données, permettant au consommateur d'exprimer leur intérêt. Ceci est en contraste à...

Pousser

Push Api sont un bon ajustement pour quand quelque chose est de générer des données, et les données générées ne se soucie pas de savoir si quelqu'un la veut ou pas. Par exemple, peu importe si quelqu'un est intéressé, il est toujours vrai que votre souris est déplacée, et puis vous avez cliqué quelque part. Vous voulez manifester ces faits avec un push API. Ensuite, les consommateurs---peut-être plusieurs d'entre eux---pouvez vous abonner, à pousser des notifications au sujet de telles choses se produire.

L'API en elle-même ne se soucie pas de savoir si zéro, un, ou plusieurs consommateurs s'abonnent. C'est juste manifestant un fait à propos de choses qui s'est passé dans l'univers.

Les événements sont une simple manifestation de cette. Vous pouvez vous abonner à un EventTarget dans le navigateur, ou EventEmitter dans Node.js et soyez informé des événements qui sont expédiés. (Généralement, mais pas toujours, par la EventTarget du créateur).

Les phénomènes Observables sont une version plus raffinée de EventTarget. Leur principale innovation est que l'abonnement en lui-même est représenté par un objet de classe, les Observables, que vous pouvez ensuite appliquer combinators (tels que filtre, map, etc...) plus de. Ils font aussi le choix de réunir les trois signaux (généralement nommé prochaine, complète, et l'erreur) en un seul, et de donner à ces signaux spéciaux de la sémantique, de sorte que les combinators les respecter. C'est par opposition à EventTarget, où les noms d'événements n'ont sémantique (aucune méthode de EventTarget se soucie de savoir si votre événement est "complete" vs "faa"). EventEmitter dans le Nœud a une certaine version de ce spécial-la sémantique de l'approche "erreur" événements peuvent se bloquer le processus, mais c'est assez primitif.

Une autre fonctionnalité intéressante de phénomènes observables sur le cours des événements, c'est que généralement, seul le créateur de l'observable, peuvent être la cause de générer de ceux suivant/erreur/complète des signaux. Alors que sur EventTarget, n'importe qui peut appeler dispatchEvent(). Cette séparation des responsabilités permet un meilleur code, dans mon expérience.

Mais en fin de compte, à la fois les événements et les phénomènes observables sont de bonne Api pour pousser les occurrences dans le monde, pour les abonnés qui peuvent se brancher et régler à tout moment. Je dirais observables sont le plus moderne pour ce faire, et plus agréable à certains égards, mais les événements sont de plus en plus répandue et bien compris. Donc, si quelque chose a été prévu pour remplacer les événements, il serait observables.

Poussez <-> pull

Il est intéressant de noter que vous pouvez construire une ou l'autre approche sur le dessus de l'autre en un clin d'œil:

  • Pour construire pousser sur le dessus de tirer, être constamment en tirant à partir de la liste de l'API, puis poussez les blocs pour tous les consommateurs.
  • Pour construire tirez sur le dessus de pousser, de s'abonner à la push API immédiatement, à créer une zone tampon qui s'accumule tous les résultats, et quand quelqu'un tire, le saisir à partir de la mémoire tampon. (Ou attendre jusqu'à ce que le tampon est vide, si votre consommation est en tirant plus vite que la enveloppé push API est de pousser.)

Ce dernier est généralement beaucoup plus de code à écrire que l'ancien.

Un autre aspect de l'essayer pour s'adapter entre les deux est que seulement tirer Api permet de communiquer facilement la contre-pression. Vous pouvez ajouter un canal latéral à pousser des Api pour leur permettre de communiquer à la pression de retour vers la source; je pense Dart fait cela, et certaines personnes essaient de créer des évolutions des observables qui ont cette capacité. Mais c'est de l'OMI beaucoup plus difficile que tout juste correctement du choix d'un pull API en premier lieu. Le revers de la médaille, c'est que si vous utilisez un push API pour exposer fondamentalement basé sur l'extraction de la source, vous ne serez pas en mesure de communiquer la contre-pression. C'est l'erreur faite avec le WebSocket et XMLHttpRequest Api, par la manière.

En général, je trouve les tentatives pour unifier le tout dans un API en l'enveloppant d'autres erronée. Pousser et tirer distincts, pas-très-chevauchement des domaines où elles fonctionnent bien, et dire que nous devrions choisir l'un des quatre Api que vous avez mentionné et le bâton avec elle, comme certaines personnes le font, est à courte vue et conduit à adopter de code.

5voto

kirly Points 51

Ma compréhension de la Async Itérateurs est un peu limité, mais ce que je comprends WHATWG, les Ruisseaux sont un cas particulier de la Async Itérateurs. Pour plus d'informations, veuillez vous référer à l' API de Flux FAQ. Il traite brièvement de la façon dont diffère de phénomènes Observables.

Les deux Async les Itérateurs et les Observables sont des méthodes génériques pour manipuler plusieurs asynchrone valeurs. Pour l'instant, ils ne sont pas interop mais il semble que la création d'Observables à partir Async Itérateurs est envisagée. Observables par leur poussée en fonction de la nature sont beaucoup plus semblables que l'actuel système d'événement, AsyncIterables étant basé sur du pull. Une vue simplifiée serait:

-------------------------------------------------------------------------    
|                       | Singular         | Plural                     |
-------------------------------------------------------------------------    
| Spatial  (pull based) | Value            | Iterable<Value>            |    
-------------------------------------------------------------------------    
| Temporal (push based) | Promise<Value>   | Observable<Value>          |
-------------------------------------------------------------------------    
| Temporal (pull based) | await on Promise | await on Iterable<Promise> |
-------------------------------------------------------------------------    

Je l'ai représenté l' AsyncIterables comme Iterable<Promise> pour faire une analogie plus facile de raisonner sur. Notez que await Iterable<Promise> n'est pas significative, comme il doit être utilisé dans un for await...of AsyncIterator boucle.

Vous pouvez trouver une explication plus complète ici.

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