ventajas rxjava reactivas reactiva que programación programacion desventajas arquitectura aplicaciones reactive-programming frp reactivex

reactive programming - rxjava - ¿Se considera Reactivo X la programación reactiva?



programación reactiva rxjava (2)

Autor de la biblioteca de banano reactivo aquí.

La distinción clave entre la programación reactiva funcional (FRP) y la programación reactiva (RP) es que la primera tiene una semántica denotacional bien definida, generalmente obtenida de los tipos

type Behavior a ~= Time -> a type Event a ~= [(Time, a)]

mientras que este último no tiene una semántica denotacional bien definida. En particular, todas las implementaciones de RX que conozco sufren el problema de que la fusión de secuencias de eventos no es determinista : cuando las secuencias contienen eventos simultáneos, a veces una aparición se fusiona antes que la otra, y otras al revés.

Además, la afirmación de que "FRP funciona con valores que cambian continuamente con el tiempo" es sutilmente incorrecta y no es la diferencia clave:

  • Primero, el análisis más probable para esta afirmación es que "Los comportamientos son funciones continuas Time -> a ", lo que no es cierto: los comportamientos pueden ser discontinuos, por ejemplo, pueden ser funciones de pasos. Lo que es cierto, en cambio, es que el Time en FRP generalmente se toma como un número real, es decir, un continuo de valores.
  • Segundo, es perfectamente posible tener FRP donde el tiempo es discreto. Esa no es la diferencia clave para RP, sino que se trata de si sus operaciones en valores tienen una semántica de denotación bien definida o no.

Desde la página de introducción de ReactiveX :

A veces se le llama "programación reactiva funcional", pero esto es un nombre inapropiado. ReactivoX puede ser funcional y reactivo, pero la "programación reactiva funcional" es un animal diferente . Un punto de diferencia principal es que la programación reactiva funcional opera con valores que cambian continuamente con el tiempo, mientras que ReactiveX opera con valores discretos que se emiten con el tiempo.

Mientras tanto, en la página de Programación reactiva funcional de Wikipedia , ReactiveX aparece en la sección "Implementaciones":

Implementaciones [editar]

  • cellx, Implementación ultrarrápida de reactividad para javascript
  • Elm, lenguaje FRP que compila a HTML, CSS y JavaScript
  • Implementación de Frappuccino FRP en Ruby
  • Flapjax, comportamiento / evento de implementación de FRP en JavaScript
  • Reactive.jl, implementación de FRP en Julia
  • ReactiveX, implementación de FRP en múltiples idiomas, incluyendo Java, JavaScript, Python, Swift y muchos más
  • Implementación de FRP de banano reactivo en Haskell
  • ReactiveCocoa FRP implementado en Swift y Objective-C
  • ReactiveKit FRP implementado en Swift puro
  • Implementación de FRP Reflex en Haskell
  • Implementación de Scala.Rx FRP en Scala (y Scala.js)
  • Sodio, implementación de FRP en C #, C ++, Haskell (en desuso [12]), Java,> Rust y Scala
  • Implementación de Yampa FRP en Haskell.

Entiendo muy bien lo que hace ReactiveX, y también hice algunas investigaciones sobre "Programación reactiva" y "Programación reactiva funcional", pero todavía no puedo distinguir las relaciones entre ellos.

De hecho, creo que la página de Wikipedia es errónea, o que enumera incorrectamente los ejemplos en la sección "Implementaciones", ya que sé que cellx y ReactiveX (que se enumeran en los ejemplos) están diseñados para resolver problemas completamente diferentes.


Por lo que yo entiendo, desde el punto de vista de ReactiveX (también conocido como RX), es simplemente imposible que dos eventos ocurran al mismo tiempo. Estos son solo devoluciones de llamada que se activan internamente, secuencialmente, en el orden de suscripción . RX no "gestiona" el tiempo.

RX puede actuar bastante loco como se ve a través de los ojos de un programador de FRP puro. Considere el siguiente código RXJS:

const xs = Rx.Observable .interval(0) //.share(); xs.combineLatest(xs, (a,b) => [a,b]) .filter(ab => ab[1] > ab[0]) .take(1) .subscribe(ab => alert(ab));

Aquí xs es un intervalo observable frío que se dispara lo más rápido posible. Como xs.combineLatest(ys, f) siempre se suscribe a xs primero, luego a ys , usted esperaría que xs.combineLatest(xs, (a,b) => [a,b]) produzca [0,0], [1,0], [1,1], [2,1], ... Entonces ab[1] > ab[0] siempre debe ser falso. Sin embargo, en mi PC, si mantengo este código en ejecución por un tiempo, termina en algún momento , podría tomar un tiempo, pruébelo usted mismo

Esto se debe a que xs es un frío observable: cada suscripción a interval creará un temporizador periódico que se ejecuta de forma independiente. Estos temporizadores pueden y lo harán en algún momento en un orden diferente (especialmente en entornos de subprocesos múltiples como .NET)

Si comentamos la //share línea //share , haciendo que xs esté caliente , la secuencia nunca se completa, como [0,0], [1,0], [1,1], ... ,[i,i-1],[i,i]... ahora se genera de manera determinista. Esto es porque un observable caliente comparte una sola suscripción. En este caso, solo se crea un temporizador.

En un sistema de FRP real, este comportamiento sería determinista. Sin embargo, si realmente se conectara a diferentes temporizadores de hardware en un sistema FRP real, también obtendría el mismo comportamiento que RX, ya que estos eventos externos se activarán en orden aleatorio, a menos que los dos temporizadores estén perfectamente sincronizados, por supuesto.