13

Soweit ich verstehe, sind die folgenden Techniken asynchrone Programmierung Workflows zu lösen:Wie vergleicht Observables (Rx.js) mit ES2015-Generatoren?

  1. Rückrufe (CSP)
  2. Promises

Neuere Ansätze:

  1. Rx.js Observables (oder mostjs, speck.js, xstream usw.)
  2. ES6 Generatoren
  3. Async/Await

Wir jetzt bewegen sich von Rückrufe entfernt & Versprechen zu diesen neueren Ansätzen. Was ich derzeit verstehe ist - Async/Await ist mehr wie eine sauberere Abstraktion auf ES2015 Generatoren.

Was ich nicht verstehen kann, ist der konzeptionelle Unterschied zwischen Observablen und Generatoren. Ich habe beide ausgiebig benutzt und habe keine Probleme sie zu benutzen.

Was mich verwirrt ist der Anwendungsfall für Observables und Generatoren. Ich bin zu dem Schluss gekommen, dass sie am Ende das gleiche Problem angehen - Asynchronität. Nur der potentielle Unterschied, den ich sehe, ist, dass Generatoren inhärent eine imperative Semantik zum Code bereitstellen, während Observables, die Rxjs verwenden, ein reaktives Paradigma zu liefern scheinen. Aber ist es das?

Sollte das das Kriterium sein, zwischen Observable und Generator zu wählen? Was sind die Vor- und Nachteile?

Fehle ich das große Bild?

Auch mit Observable schließlich in Zukunft Ecmascript machen, werden Promises (mit cancelable-Token)/Observable/Generatoren miteinander konkurrieren?

+3

ein paar Anmerkungen: Async/Await auf Versprechungen baut, nicht Generatoren. Außerdem wurde der annullierbare Promise-Vorschlag kürzlich zurückgezogen. –

+1

Wie Äpfel mit Orangen. Sie sind verschiedene Muster. Generatoren haben nichts mit Asynchronität zu tun. Wenn Sie sie benutzt haben, sollten Sie das wahrscheinlich wissen. Generatoren bieten ein Muster, das für einen asynchronen Kontrollfluss geeignet ist ("co" oder TS async/wartet auf die Implementierung für das ES6-Ziel), aber das ist alles. – estus

+0

@estus, Ja. Generator ist keine wirklich asynchrone Lösung. Generator ist mehr wie eine Fabrik von Iteratoren. Wie Sie bereits erwähnt haben, löst es jedoch asynchrone Probleme durch Hinzufügen von "Q" - oder "Co" -Steuerflüssen. –

Antwort

8

Observables Push-Änderungen, und damit das Observable, nicht die Funktion, die darauf reagiert, hat die Kontrolle. Auf der anderen Seite müssen Generatoren Werte aus ihnen ziehen. Die Funktion, die auf den neuen Wert reagiert, legt fest, wann sie für einen neuen Wert bereit ist.

Ich hatte Probleme mit Gegendruck mit Observables, aber mit Generatoren können Sie Werte so langsam wie Sie wollen lassen.

Edit: die letzte Frage. Versprechen sind nur Observable, die nur einmal ausstrahlen, also glaube ich nicht, dass sie miteinander konkurrieren werden. Ich denke, der wahre Kampf wird async/erwarten vs Observables sein, und async/erwarten hat einen Vorsprung, und ist bereits in C# (und jetzt Node.js). Aber Observables haben dieses süße FRP-Feeling, und funktionales Programmieren ist super cool, also denke ich, dass sie beide mit einem guten Stück Verstand enden werden.

Edit2: André Staltz, Autor von Cycle.js und xstream, und Mitarbeiter Rx.js, schrieb ein großen Artikel auf, wie Generatoren und Observable beziehen (auf 2018.01.31). Insbesondere zeigt er, wie sie beide von einer gemeinsamen Basisklasse erben.

Und jetzt ein Verbraucher kann ein Listener ("Beobachter") oder ein Puller sein, es liegt an dem Verbraucher, ob es den Produzenten ziehen wird oder nicht.Und der Produzent kann ein Listenable ("beobachtbar") oder ein Pullable ("iterierbar") sein, es liegt beim Hersteller, ob er Daten proaktiv oder nur bei Bedarf sendet. Wie Sie sehen können, Verbraucher und Produzenten sind einfache Funktionen des gleichen Typs:

(num, Nutzlast) => void

So dass jeder Betreiber, die wir reaktive Programmierung oder iterable Programmierung bauen sowohl für die Arbeit, einfach weil die Grenze zwischen diesen beiden Modi unscharf wird und es nicht mehr um Observables im Vergleich zu Iterablen geht, geht es nur um Datentransformationen zwischen Produzenten und Konsumenten.

Ich empfehle es zu lesen [link]. Der Artikel stellt "Callbags" vor, eine Spezifikation für Rückrufe, die für reaktive und iterierbare Programmierung verwendet werden. Er implementiert diese Spezifikation, um a tiny library für iterable und reaktive Programmierung zu machen. Locken Sie den Artikel zu lesen und die Bibliothek zu überprüfen, sind hier einige Beispiele aus der 7kb lib basierend auf der Spezifikation stellt er:

Reactive Programmierbeispiel

Wählen Sie die ersten 5 ungerade Zahlen von einer Uhr dass jede Sekunde tickt, dann beginnen sie zu beobachten:

const {forEach, interval, map, filter, take, pipe} = require('callbag-basics'); 

pipe(
    interval(1000), 
    map(x => x + 1), 
    filter(x => x % 2), 
    take(5), 
    forEach(x => console.log(x)) 
); 

// 1 
// 3 
// 5 
// 7 
// 9 

Iterable Programmierbeispiel

aus einem Bereich von Zahlen, von denen 5 aufzunehmen und sie durch 4 dividieren, dann anfangen, diese eine nach der anderen ziehen:

const {forEach, fromIter, take, map, pipe} = require('callbag-basics'); 

function* range(from, to) { 
    let i = from; 
    while (i <= to) { 
    yield i; 
    i++; 
    } 
} 

pipe(
    fromIter(range(40, 99)), // 40, 41, 42, 43, 44, 45, 46, ... 
    take(5), // 40, 41, 42, 43, 44 
    map(x => x/4), // 10, 10.25, 10.5, 10.75, 11 
    forEach(x => console.log(x)) 
); 

// 10 
// 10.25 
// 10.5 
// 10.75 
// 11 
0

Sie können die rxjs Observablen als Asynchrongeneratoren d.h. Generatoren Nachgeben Versprechungen berücksichtigen. Nur weil der Inhalt nicht garantiert ist an der Zeit zu sein, sind wir bereit, .next nennen (im Gegensatz zu den regulären Generatoren)

  • Der Teilnehmer permanent des Generators Inhalt (Aufruf .next) verbrauchen wird in eine Endlosschleife
  • Warten Sie auf das zurückgegebene Versprechen zu lösen (oder widerrufen) zu tun, was Sie wollen
  • Die Observable (mit einem asynchronen Generator gemacht) wird auf die Generatoren zurückkommen.

More reading

asynchronous Iterators proposal