Matrix

AngularJS Knockout React Elm RxJS, Bacon ReactiveCoffee Warp9
template based yes/no[1] yes no no no no
controls composability no[2][3] no[2] yes yes yes yes
modularization of controls yes/no[4] no yes maybe yes yes
2 way binding yes/no[5] yes no yes yes yes yes
accidental memory leaks no yes no ? ? yes no
diamond shape problem no yes no ? ? yes no
observable inconsistent state no yes/no[6] no ? ? yes no
todomvc yes yes yes no maybe yes/no[7] yes
headless no yes no no yes yes yes
pure js yes yes yes[8] no yes no yes
mixing markup and logic yes/no[9] no yes yes yes yes
simplicity no yes yes yes yes yes yes
rich reactive list no ? no yes

RxJS and Bacon are great libraries to compose events, but to build UI you need an ability to compose not only events, but a UI primitives too. So you can't pick one and build an UI using this library only (actually you can, but you end with dealing with DOM from event handler). I included them only to highlight difference between reactive UI libraries and reactive libraries "to compose asynchronous and event-based programs".

Legend and notes

template based

Whether the templates are primary method for building UI
[1] if you look through tutorials and examples you'll find that Angular is definitely template based, but when you decide to define a custom directive you'll meet an another side of Angular (unless you use templateUrl of cause).

controls composability

Whether the library provides building controls (view) via composing existing ones (divide and conquer principle).

[2] Angular and Knockout allow to break templates into sub templates, place them to different files and include via provided mechanisms (ng-include, template-binding). But it doesn't imply that angular and knockout support modularization and composability of controls.

Don't forget that a complex UI isn't static - it has a behaviour. From semantic perspective this behaviour is high coupled with view, but Angular and Knockout separate behaviour from templates and place it to comptrollers, so if we do something with templates (like composing) we have to keep in mind the behaviour. Does it look familiar? If it were code we would call it side-effect. No matter the nature but any side-effect kills composability, this is the reason why I can't say Angular and Knockout provide it.

I'm not the only one who notices it, the creators of React write:

“React doesn't use templates... ...React is a library for building composable user interfaces.”

If you are still in doubt, think about why the are so few template engine for creating desktop application if the templates are so great.

[3] The only way to create a composable Angular application is to implement it using only custom directive.

modularization of controls

Whether it is possible to pack control (component or combination of template and controller) in a form which is appropriate for distribution and easy to attach to an application.

[4] It is possible with Angular to use AMD to achieve modularization as long as your control is directive created without us of 'templateUrl'.

binding & 2 way binding

Whether it is possible to bind one reactive variable to another and to use bidirectional binding between control and variable.

[5] Angular has a way to bind controls and variable, but it can't bind variable and variable.

accidental memory leaks

Whether it is easy to write code that looks fine but leaks with the library. It happens that for all library for which it is true it is also true that code with leaks looks significantly easy than equivalent code without leaks. That means that if you are using such libraries well they lose its elegance.

I've written simple application using Knockout and ReactiveCoffee to demonstrate how easy a leaks can be achieved: app on Knockout и app on ReactiveCoffee. And of cause the same app on Warp9 without leaks.

Repeated diamond shape problem

Whether it possible to form a dependency graph in such way that a single update to a one reactive variable causes multiple updates to another.

I described that situation a bit more and demonstrate with Knockout and ReactiveCoffee.

Observable inconsistent state

Whether it possible to observe an inconsistent state due to the lack of atomic updates. Also this problem is described a bit more on a separate page.

[6] Knockout has a workaround to simulate atomic updates but such workaround violates locality of change and breaks composability. There is an information on the topic.

todomvc

TodoMVC is a standard 'hello word application' for various web UI libraries, it is rule of etiquette for library's author to provide an TodoMVC among examples.

[7] TodoMVC on ReactiveCoffee isn't follow the spec properly, it lacks for tabs ('All', 'Active', 'Completed') and work with local storage (at least on 5 Nov 2013).

headless

Whether it is possible to use application on server side for dealing, for example, with events.

pure js

Has author assumed that the library would be used basically with javascript language?

[8] React offer to use javascript's dialect with build in support for xml literals and compile it to javascript, nevertheless it is possible to use pure javascript.

mixing markup and logic

Does library suggest to mix markup and logic.

It is a common thought that it isn't good and we should separate them. But such approach introduces more problem then solves when we build complex application.

Since UI is a behaviour and behaviour is described by markup and logic, it should be obvious that markup and logic are highly coupled - when we edit markup we should think about code and when we edit code we should think about markup, especially when we store them separately, sounds like side-effect, right? Another point against the separation is complexity of tools. If we store markup and logic separately and our application is big enough we need ways for composition/modularization of markup and ways for composition/modularization of code - we double the count of entities, which is bad, according to Occam.

There is another way to fight complexity - to extract independent behaviour (mix of markup & logic) to controls (abstraction) and to apply use the composition principle to those base controls to build a new one, more complex up to the needed application. There is an analogy to complexity theory: dividing application into markup and code reduce the complexity by factor of 2 (n -> n/2), but abstraction and composition (divide and conquer) reduce it logarithmically (n -> ln (n)).

It is a interesting to notice that libraries forcing you to mix markup and code provide composition and modularization.

[9] You may meet the need of mixing markup and code during developing a directive in Angular.

simplicity

Is the number of entities which the library introduces few?

This is very subjective but I think that are a lot of entities in Angular. By the way the developers of React shares this opinion:

Number of concepts to learn
  • React: 2 (everything is a component, some components have state). As your app grows, there's nothing more to learn; just build more modular components.
  • AngularJS: 6 (modules, controllers, directives, scopes, templates, linking functions). As your app grows, you'll need to learn more concepts.

rich reactive list

Almost all reactive libraries provides primitives for working with reactive variables, such as creation of new reactive variable bound with function to another. In knockout you can do it this way:

var a = ko.observable(0);
var b = ko.compute(function() { return a() + 2 });
In warp9:
var a = new Cell(0);
var b = a.lift(function(a) { return a+2; });

But when we look at lists, its support is limited in Knockout and ReactiveCoffee, if we omit some details we find that in those libraries reactive list is just a reactive variable which contains a list. So if you need to do list aggregation and you want this aggregated value to be a reactive variable, you have to redo whole aggregation on each update. For example, if you make a sum aggregation of list and add n values to it then you end with O(n2/2) computations with Knockout or ReactiveCoffee, but only with O(n) with Warp9. Moreover Knockout or ReactiveCoffee don't provide method to do aggregation over reactive list filled with reactive variables, but Warp9 does and your aggregated value will be automatically updated when a reactive list changes or any its reactive variable changes. Example:

var list = new List([new Cell(0), new Cell(1), new Cell(2)]);
var sum = list.reduce(0, function(a,b) { return a + b; });