Core.async en Functioneel Reactief Programmeren (+Rx) vergelijken

Ik schijn een beetje in de war te zijn als ik Clojure’s core.asyncvergelijk met de zogenaamde Reactive Extensions(Rx) en FRPin algemeen. Ze lijken een soortgelijk probleem van asynchrone problemen aan te pakken, dus ik vraag me af wat de belangrijkste verschillen zijn en in welke gevallen de ene de voorkeur heeft boven de andere. Kan iemand het alsjeblieft uitleggen?

EDIT: om meer diepgaande antwoorden aan te moedigen, wil ik de vraag specifieker maken:

  1. Met Core.async kan ik synchroon uitziende code schrijven. Zoals ik het echter begrijp, heeft FRP slechts één niveau van geneste callbacks nodig (alle functies die logica verwerken, worden als argumenten doorgegeven aan de FRP API). Dit lijkt erop dat beide benaderingen het terugbellen van piramidesoverbodig maken. Het is waar dat ik in JS vaak function() {...}moet schrijven, maar het grootste probleem, de genestecallbacks, is ook in FRP verdwenen. Begrijp ik het goed?

  2. FRPcomplecteert de communicatie van berichten met flow of control” Kunt u (iemand) een meer specifieke uitleg geven?

  3. Kan ik de waarneembare eindpunten van FRP niet op dezelfde manier doorgeven als kanalen?

Over het algemeen begrijp ik waar beide benaderingen historisch vandaan komen en ik heb in beide weinig tutorials geprobeerd. Ik schijn echter “verlamd” te zijn door de niet-duidelijkheid van verschillen. Is er een voorbeeld van een code die moeilijk te schrijven is in een van deze en gemakkelijk te gebruiken in de andere? En wat is daar de architecturale reden van?


Antwoord 1, autoriteit 100%

Ik denk dat het belangrijkste probleem is dat uw veronderstelling over het aangepakte probleem niet helemaal waar is, aangezien geen van hen het “probleem” van asynchroniciteitaanpakt.

De abstracties

Het hoofdidee van

FRPis het verspreiden van verandering, denk erover hetzelfde te bereiken als Excel doet, waarbij je cellen definieert die van elkaar afhankelijk zijn in een cascade, en wanneer een cel verandert, worden alle afhankelijke cellen in de cascade opnieuw berekend.

Het hoofdidee van

core.asyncis de ontleding van systemen, denk aan het scheiden van zorgen met behulp van een queuein het midden van verschillende processen, in core.asyncin plaats van wachtrijen heb je kanalen, maar je snapt het idee.

Het verwijderen van de piramidale codeis dus niet het doel van beide technologieën, en ze werken op verschillende abstractielagen.

Over het completeren van de regelstroom

Het idee over het completeren van communicatie en flow control is afkomstig van het oorspronkelijke asynchrone kernbericht.

Hoewel er verschillende mechanismen zijn om gebeurtenissen/callbacks schoner te maken (FRP, Rx/Observables), veranderen ze hun fundamentele aard niet, namelijk dat bij een gebeurtenis een willekeurige hoeveelheid andere code wordt uitgevoerd, mogelijk op dezelfde thread , wat leidt tot vermaningen zoals “doe niet te veel werk in uw handler”, en zinnen als “callback hell”.

Herformuleren: als je bedrijfsdomeincodein een gebeurtenishandler hebt, heb je de X-gebeurtenisverwerkingvoltooid met de wat te doen als X gebeurt.

Dat is wat core.asyncaanpakt, aangezien het introduceren van een wachtrij/kanaalin het midden helpt voor een betere scheiding van zorgen.

Implementatie

Al uw vragen met betrekking tot callbacks en het doorgeven van waarneembare eindpunten als parameters zijn slechts implementatievragen, het hangt echt af van de Rx-implementatie en API.

Als je kijkt naar Reageer herbruikbare componenten, dan doe je dat echt niet heb veel van een callback-hel om te zien, en je krijgt het idee om waarneembare dingen door te geven.

Laatste gedachten

Zelfs als Rxkan worden gebruikt om een ​​gegevensstroom te modelleren, wordt het vaker gebruikt voor UI Renderinga-la Excel, om te vereenvoudigen hoe u uw weergave bijwerkt wanneer uw modelwijzigingen.

Aan de andere kant kan core.asyncworden gebruikt om de scheiding van zorgen te modelleren wanneer twee subsystemen met elkaar communiceren (hetzelfde gebruiksscenario als wachtrijen), door het te gebruiken voor de UI-weergave hoofdidee van de ketting is om te scheiden:

  • Genereren en verwerken van server-side-events
  • Hoe die gebeurtenis uw model beïnvloedt

U kunt dus core.asyncen FRPsamen hebben, aangezien core.asynczorgen scheidt, en FRPdefinieert uw trapsgewijze gegevensstroom zodra uw model is bijgewerkt.


Antwoord 2, autoriteit 78%

Ten minste een van de belangrijkste belangrijkste verschillen, en, denk ik, wat Rich ment by “[FRP] de communicatie van berichten met flow of control compliceert”, is het volgende.

Callbacks zijn code die wordt uitgevoerd. En die uitvoering moet op een bepaald moment in een of andere thread plaatsvinden. Vaak is het moment waarop de gebeurtenis plaatsvindt, en de draad is de draad die de gebeurtenis opmerkt/produceert. Als de producer in plaats daarvan een bericht op een kanaal plaatst, ben je vrij om het bericht te consumeren wanneer je wilt, in welke thread je maar wilt. Dus callbacks, die in wezen een vorm van communicatie zijn, completeren de communicatie met flow of control door te dicteren wanneer en waar de callback-code wordt uitgevoerd. Als je om wat voor reden dan ook terugbellen moet gebruiken, gebruik ze dan om een ​​bericht in een wachtrij/kanaal te plaatsen en je bent weer op het goede spoor.

Omdat core.async minder complex is, verdient het de voorkeur zolang er geen goede reden is om de alternatieven te gebruiken.


Antwoord 3, autoriteit 38%

Clojure core.async is een blokken van de Go-taal. Het fundamentele concept zijn kanalen die asynchrone communicatie tussen threads vertegenwoordigen.

Het doel is om normaal uitziende blokken met sequentiële code te kunnen schrijven die toegang hebben tot kanalen om invoer te krijgen, en dit wordt naadloos vertaald in een toestandsmachine die de CSPvertaling voor jou.

In tegenstelling tot FRP, dat nog steeds fundamenteel draait om terugbellen, en het compliceert de communicatie van berichten met flow of control. core.async elimineert callbacks van uw code volledig en scheidt de controlestroom van de berichtoverdracht. In FRP is een kanaal ook geen eersteklas object (je kunt een FRP-kanaal niet als een waarde op een FRP-kanaal verzenden).


Antwoord 4, autoriteit 16%

BEWERKEN:

Om uw vragen te beantwoorden:

  1. Ja, vaak kunnen callbacks worden geëlimineerd, bijvoorbeeld met logica voor opnieuw proberen, distinctUntilChanged en tal van andere dingen, zoals:

    var obs = getJSON('story.json').retry(3);

    var obs = Rx.Observable.fromEvent(document, 'keyup').distinctUntilChanged();

  2. Ik weet niet zeker waar dat naar verwijst als je het ingewikkelder maakt met stroomregeling.

  3. Ja, je kunt rond een object gaan zoals je een kanaal zou doen, zoals bij het onderstaande object.

Je kunt hier bijvoorbeeld kanaalachtig gedrag vertonen met RxJS met een ReplaySubject:

var channel = new Rx.ReplaySubject();
// Send three observables down the chain to subscribe to
channel.onNext(Rx.Observable.timer(0, 250).map(function () { return 1; }));
channel.onNext(Rx.Observable.timer(0, 1000).map(function () { return 2; }));
channel.onNext(Rx.Observable.timer(0, 1500).map(function () { return 3; }));
// Now pass the channel around anywhere!
processChannel(channel);

Om het een beetje concreter te maken, vergelijk de code uit het bericht van David Nolen hiermet een RxJS FRP-voorbeeld hier


Antwoord 5, autoriteit 12%

Er is hier een post die FRP vergelijkt met CSP op een beperkt aantal voorbeelden (die echter bedoeld waren om de voordelen van CSP aan te tonen), met een conclusie aan het einde: http://potetm.github.io/2014/01/07/frp.html

Other episodes