reactive.coffee

Related Work and Comparisons

There is no shortage of client-side framework for building rich web app UIs. This section will mainly focus on trade-offs and differences; to be clear, these are all just opinions of the original author, who has deep respect for the work of these other library authors, and liberally draws inspiration from them. Ideally, there wouldn't have been a need to create Reactive.

  • Any of the multitude of declarative UI toolkits based on reactive programming, especially FRP in the Haskell universe, but also Bling, FlapJax, and others rooted more in the programming languages community.

  • Specifically in JS land: Knockout in terms of the mechanics behind observables and computed observables, but with fewer moving parts and API surface (no read/write interception, context management, etc.). Reactive originally tried simply reusing KO, but ultimately divorced itself since there are both desired features that are missing (differences in array event propagation, topologically ordered batch propagations, etc.) and features that are unwanted (mis-matched programming model, larger API surface area, etc.).

    For its HTML-based template language it uses a micro-syntax in data-bind attributes to bind to element properties to expressions.

    A number of reactive programming libraries in JS besides Knockout including React.js, Reactor, RxJS and bacon.js. Some of these libraries also aren't quite the same in that they still require you to explicitly specify the subscriptions and use combinators to merge different streams.

    Reactive is more similar to Knockout than it is to Backbone (see this Stack Overflow answer for more).

  • Angular is a popular framework that emphasizes testability. The template language extends HTML with its own directives. Unfortunately it employs much more magic, has a steep learning curve, and is significantly larger and more complex. Khan Academy's Ben Alpert's critique is not uncommon:

    Angular documentation for how to write a directive (a reusable component) needs to explain directive priorities, the difference between compiling and linking, the creation of new scopes, and transclusion, all of which are Angular-specific concepts.

    There exist numerous other critiques of Angular---here's but a small sample:

    Angular eschews change listeners for model diff computation. This is to be distinguished from React's view diff computation—Angular does not need to construct a lightweight DOM to diff since it is aware of the dependencies, since its bindings are restricted to simple path-like accessors against the current scope (with optional filters). However, it must compute changes in the model in a process it calls dirty checking, which does not scale and has historically been source of code complexity.

  • Ember offers its own template language that feels right at home if you are coming from a server-side templates background. It has a Mustache-ish template language that, like Angular, uses simple path-like accessors against the current context, but with a mix of Ember-specific directives such as action, link, bindAttr, outlet, helpers, etc. The framework introduces its own class/object model, and also uses explicit Controller objects to tie together models and views.

  • Polymer for its brazen use of new but unstable technologies such as Object.observe, Web Components, and Shadow DOM. Some good ideas here, but there's still a good deal of platform/tooling immaturity as well as more verbose scaffolding around creating components and defining reactive behaviors.

  • React shares a similar approach of leveraging a full programming language (JS) rather than a more restrictive template language for declaratively assembling UI components, as well as a similar focus on only one-way data bindings. Beyond view rendering, React does not provide reactive programming primitives for the rest of your application.

    React encourages use of JSX, which is a syntactic transform over JS and comes with its own set of subtle differences from HTML, besides the usual complexities of integration into existing frameworks and pipelines.

    It imposes a more heavyweight component model with a more complex API that has a greater surface area. There are a number of core concepts to learn: properties, refs, state, "classes", mixins, lifecycle management (component[Will|Did]Mount, unmountAndReleaseReactRootNode, etc.), property transfer, controlling update propagation (shouldComponentUpdate, componentWillReceiveProps, etc.), and more. React also requires its own way of doing things such as low-level DOM manipulation—something that Reactive intentionally delegates to jQuery.

    React, like WebFUI, re-constructs a lightweight representation of the entire updated DOM and computes diffs to determine what actual DOM operations to execute. Programmability-wise, this is not as straightforward as working with the actual DOM objects, requiring some awkward concepts such as refs, and this does lead to some tricky situations involving the predictability of re-rendering and also the control of things such as element focus. Performance-wise, the approach is adequate for certain classes of applications/contexts, though the process takes on the order of 1ms in a modern desktop/laptop browser for simple applications such as TodoMVC. For other applications or on mobile devices, performance/battery life do unfortunately matter. This is more frequently the case as rich client-side application complexity grows. Consider a browser-based Photoshop clone—smooth dragging controls affecting a small number of on-screen components cannot incur the full DOM diff algorithm per frame.

    Feel free to dig into our clone of the React tutorial, under examples/react-tut/.

  • Visage, formerly known as JavaFX, introduces incremental evaluation in a statically typed scripting language for the JVM. It focuses on building Swing UIs. Reactive was actually originally inspired by its approach, which is also one of using a full programming language to host the declarative UI construction, along with its intuitive syntax for creating bindings. JavaFX used compile-time transforms to implement incremental evaluation.

  • CoffeeKup is another CoffeeScript-embedded DSL for constructing (static) DOMs