

Transparent Reactive Programming - primigenus
https://github.com/meteor/meteor/wiki/Tracker-Manual

======
voidhorse
I've been playing with/learning meteor for the past week. The reactivity is no
doubt a great feature. It's a great joy to develop with meteor too, with hot
code pushes, the app automatically updates to include your file changes on the
fly. It's great.

The ability to create custom reactive objects is sweet. Plus you can stop
reactivity on the fly. Thus far I'm really enjoying it.

------
mrgalaxy
Meteor's reactive style is so incredibly powerful that it's useful even
outside the Meteor ecosystem. In case anyone is looking to use this, I made a
fork of Meteor's Tracker for use in any Node.js or browser app:
[https://www.npmjs.com/package/trackr](https://www.npmjs.com/package/trackr)
(shameless plug)

------
muraiki
I'm quite tired so I might be mistaken here, but autorun reminds me of
Knockout's computed properties.

    
    
      function viewModel() {
        this.observable = ko.observable();
        this.updateWhenObsChanged = ko.computed(function() {
          console.log(this.observable());  // logs whenever the observable changes
          return this.observable();  // see template example below
        });
      }
      ko.applyBindings(viewModel);
    

Any observables used in a computed property are automatically watched. The
computed property can contain any JS code; it makes the function inside
reactive.

Knockout also has a built in templating library where you can do things like:
<p data-bind="text: updateWhenObsChanged"></p>

It seems like in this library, one area that's more flexible than KO is that
you can create various reactive data sources. However, in KO you can
essentially do the same thing by updating an observable. For instance, you
could have this.webSocketResponse = ko.observable() and call it with a new
value for every websocket response you give.

Now for me, the step beyond this is a library like Reactive Extensions (RxJS
for Javascript) which instead of having stateful observables gives you async
streams of events. For instance, say that you have two buttons, #1 and #2, and
you want to do something when button one is pressed before button two:

    
    
      var buttonOne = $('#1');
      var buttonOneClickStream = Rx.Observable.fromEvent(buttonOne, 'click');
      var buttonTwo = $('#2');
      var buttonTwoClickStream = Rx.Observable.fromEvent(buttonTwo, 'click');
      var lastTwoClicks = buttonOneClickStream
        .map(function () { return 1; }) // clicking button one produces a 1
        .merge(  // merge buttonOneClickStream's output with the buttonTwoClickStream
          buttonTwoClickStream.map(function() { return 2; }) // clicking button two produces a 2
        )
        .bufferWithCount(2); // emit an array of two values once we have two values from our merged streams
      var firstThenSecond = function (arr) {
        return arr[0] === 1 && arr[1] === 2;
      };
      var clickedFirstThenSecond = lastTwoClicks  
        .filter(firstThenSecond);  // only emit events that match our filter
      var notifyOnSuccess = clickedFirstThenSecond.subscribe(function() {
        console.log("woot");
      });
    

The nice thing about this approach is that you can build up a variety of
streams and merge them in a reusable and functional way. While this is
possible in KO, I find that unless I'm very disciplined I ended up with a mess
of computed properties scattered throughout my app. Since in KO we are using
the observer pattern, which is stateful, this can cause some complexities. But
with stateless streams, we have a more declaritive and perhaps even
"imperative" approach.

The step beyond this it to tie these streams into something more advanced than
JQuery, like virtualdom. I started working on this only to find someone else
has already accomplished a lot more than me in
[https://github.com/staltz/cycle](https://github.com/staltz/cycle) However, I
think I might like a template-based approach using something like handlebars.

Anyways I'm quite tired so I might be mistaken in my assesment of this
library. But I think anyone interested in reactive programming might like KO,
RxJS, and Cycle. KO's worked quite nicely for me, despite my complaints about
the limitations of stateful observers.

Complete example of RxJS:
[http://jsfiddle.net/bjhyvvjs/](http://jsfiddle.net/bjhyvvjs/)

How to grok reactive programming:
[https://gist.github.com/staltz/868e7e9bc2a7b8c1f754](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754)

Why React.js isn't actually reactive: [http://staltz.com/dont-
react/#/](http://staltz.com/dont-react/#/)

Edit: Argh I'm so sorry about the bad code rendering... I forgot to set
translate_tabs_to_spaces in Sublime Text :( It should be good now!

~~~
siegecraft
Hrm, do you mean that you use RxJS with knockout to alleviate the mess of
computed properties? Or switch to RxJS/Cycle entirely?

~~~
muraiki
I haven't actually tried using both RxJS and Knockout together, but it's
something I'm thinking about doing. It might seem strange to merge these two
different approaches, but I'm a fan of MVVM (which KO espouses) and of KO's
templating and component functionality. To get it working, the callback in an
RxJS subscribe method would set a KO observable, which would then be bound to
the view.

IIRC KO's author is familiar with RxJS; he made KO and reduced the concepts to
observables (of which there are similar objects in RxJS) and computed
properties as he felt it was more straightforward for the typical dev in not
requiring one to make the paradigm shift to stream composition.

I think that KO, especially when using components for encapsulation and reuse,
can be a very powerful tool. But once I started combining KO with Bluebird for
promise combinators, I started to understand the benefits of the stream-based
approach better (in RxJS promises are just another source of events, which is
a very powerful tool that I should have mentioned in the original post).

------
ratbeard
It seems like you'd have to avoid having async code inside of an autorun,
otherwise when it resumes `Tracker.currentComputation` could be different?

