Posts Tagged ‘Rx’

The Reactive Extensions for JavaScript – MooTools Integration

Sunday, March 7th, 2010 by Sebastian Markbåge

This is a follow up to my earlier post about the Reactive Extensions (Rx) for JavaScript by Microsoft’s DevLabs. This is also in response to Matthew Podwysocki’s post on jQuery integration (which deserves some credit for putting it out there).

I will assume some familiarity with Rx.

Just like any other DOM library, MooTools has a way of working with native and custom passive DOM events. We can easily give Element object and the Elements collection a method to provide these events as “Observables”. In the jQuery example the method name “ToObservable” was added to the jQuery object, accepting an event type parameter, which was my initial reaction as well. But I’m going to call mine getEvent as in “getting a stream of events given the event type“.

var observableFromEvent = function(type){
  var self = this;
  return Rx.Observable.Create(function(observer){
      var fn = function(event){
          observer.OnNext(event);
      };
      self.addEvent(type, fn);
      return function(){
        self.removeEvent(type, fn);
      };
  });
};
 
Window.implement('getEvent', observableFromEvent);
Document.implement('getEvent', observableFromEvent);
Element.implement('getEvent', observableFromEvent);
Elements.implement('getEvent', observableFromEvent);

These are infinite Observables but we could also make .destroy() trigger onComplete to make them finite as well.

Flickables Example

Instead of the canonical Drag and Drop example I thought I show a twist. Let’s say we want to listen to a mouse flick. The mouse position have to move over 100px in 200ms. Then we want the angle of the flick.

var angleFromPosition = function(position, center){
    var diffX = position.x - center.x, diffY = position.y - center.y;
    var distance = Math.sqrt(diffX * diffX + diffY * diffY);
    var angle = Math.atan2(diffY + distance, diffX) * 360 / Math.PI;
    return { distance: distance, angle: angle };
};
 
var distanceReached = function(angle){ return angle.distance > 100; };
 
var timeLimit = Rx.Observable.Timer(200);
 
var mousePositions = document.getEvent('mousemove')
                     .Select(function(event){ return event.page; });
 
var flicks = document.getElements('.flickable')
             .getEvent('mousedown')
             .SelectMany(function(event){
                 return mousePositions
                     .Select(angleFromPosition.bindWithEvent(null, event.page))
                     .TakeUntil(document.getEvent('mouseup'))
                     .TakeUntil(timeLimit)
                     .Where(distanceReached)
                     .Take(1);
             });
 
// ...
 
flicks.Subscribe(function(current){
    console.log('Flicked in direction: ' + current.angle + '°');
});

Events Mixin

MooTools has a very strong benefit compared to many other libraries. The publish/subscribe pattern is made explicit even for custom classes, using the Events mixin. By implement our “getEvent” method on this class we can use Rx on all custom MooTools classes that provide passive events.

Events.implement('getEvent', observableFromEvent);

Side-effects

Rx allows for the act of subscribing to an event to trigger an action/side-effect. Think of the Request object for example. You can use the act of subscribing to it, to issue a HTTP request. Then we can turn the subsequent events like success and failure into the Observable interface. This means that Request is a complete Observable in it self. This is what I was saving the conversion name toObservable for.

Request.implement({
 
  toObservable: function(){
    var self = this;
    return Rx.Observable.create(function(observer){
 
      var listeners = {
 
        success: function(result){
          self.removeEvents(listeners);
          observer.OnNext(result);
          observer.OnCompleted();
        },
 
        cancel: function(){
          self.removeEvents(listeners);
          observer.OnCompleted();
        },
 
        failure: function(xhr){
          self.removeEvents(listeners);
          observer.OnError(xhr);
        }
 
      };
 
      if (!self.running || self.options.link == 'cancel'){
        self.addEvents(listeners).send();
        return function(){
          self.removeEvents(listeners).cancel();
        };
      }
 
      if (self.options.link == 'chain'){
        var disposed, running;
        self.chain(function(){
          running = true;
          if (!disposed) self.addEvents(listeners).send();
        });
        return function(){
          if (running) self.removeEvents(listeners).cancel();
          disposed = true;
        };
      }
 
      observer.OnComplete();
      return function(){};
 
    });
  }
 
});

This creates a finite stream of events – only one response to be exact. However, since the act of subscribing to it causes it to occur we can have it trigger repeatedly as part of a composite stream of events.

MooTools’ Fx provides a similar concept but slightly different. Even though we don’t get an event for each tick, we still get an asynchronous complete event. This means we can insert Fx as part of a composite stream of events.

Fx also requires from/to arguments to be passed at the start. So we add the option “defaultArgs” to allow us to pass those at initialization.

Fx.implement({
 
  toObservable: function(){
    var self = this;
    return Rx.Observable.create(function(observer){
 
      var listeners = {
 
        complete: function(){
          self.removeEvents(listeners);
          observer.OnCompleted();
        },
 
        cancel: function(){
          self.removeEvents(listeners);
          observer.OnCompleted();
        }
 
      };
 
      if (!self.running || self.options.link == 'cancel'){
        self.addEvents(listeners).start.run(self.options.defaultArgs, self);
        return function(){
          self.removeEvents(listeners).cancel();
        };
      }
 
      if (self.options.link == 'chain'){
        var disposed, running;
        self.chain(function(){
          running = true;
          if (!disposed)
            self.addEvents(listeners).start.run(self.options.defaultArgs, self);
        });
        return function(){
          if (running) self.removeEvents(listeners).cancel();
          disposed = true;
        };
      }
 
      observer.OnComplete();
      return function(){};
 
    });
  }
 
});

Of course since there are a lot of other classes extending the Request and Fx classes, you get the same benefits on them. This is one of the true benefits of MooTools’ modular extensibility.

That is one of the benefits of using the class(ical) pattern in JavaScript. More on that next time…

Side-effects Example

var popup = document.id('popup');
var showPopup = new Fx.Morph(popup, { property: 'opacity', defaultArgs: 1 });
var feed = new Request.JSON({ url: 'mydata.json', method: 'get' });
 
var showFeed = feed.toObservable()
               .Do(function(data){ popup.set('text', data); })
               .Concat(showPopup.toObservable());
 
// ...
 
showFeed.Subscribe(); // loads mydata.json into #popup and displays it

Using Arrays in Unit Tests

Since natives are allowed to be extended within the MooTools theorem, we can add a convenience method to turn an Array into an observable stream of content.

Array.implement('toObservable', function(){return Rx.Observable.FromArray(this);});

We can use this to fake the “flicks” event stream in our earlier example. We avoid having to include complex asynchronous tests or user action tests.

var flicks = [
               { angle: 0, distance: 100 },
               { angle: 45, distance: 100 },
               { angle: 90, distance: 100 }
             ]
             .toObservable();
 
// Unit tests
// Synchronously testing code that's depending on a flick event stream

Web Sockets and Web Workers

Now imagine this on a stream of events coming in from Web Sockets or Web Workers.

You could set up a web socket to asynchronously feed you JSON objects, and easily hook that up to the rest of you UI just as easily as the Request example above.

The Reactive Extensions for JavaScript – Event Composition

Saturday, March 6th, 2010 by Sebastian Markbåge

I’ve been following the work on the Reactive Extensions for .NET (Rx) by Eric Meijer and others over at Microsoft. At first look I was intrigued but didn’t really understand the purpose of it. However, at a second look, I realized that it had the potential to solve every major problem I’ve had with advanced UI development in JavaScript.

Asynchronous Programming – Composable Events

Modern UI development forces us to use asynchronous patterns for user actions, animations and data load. But to make UI development easy you can think of each operation as sequential. You can even artificially lock down the user interface – by disabling or hiding UI elements – while an operation is occurring.

If you want to optimize your user experience, you will need to start dabble in the complicated art of event composition. The problem occurs when you have complex interactions that depend upon other interaction or state.

You can solve this using various state machine patterns. However, I think you will find it quite difficult at times. Even if you do solve it, it’s probably going to be for a specific purpose which is not easily generalizable nor extensible.

Various tools have tried using patterns like Futures and Promises. I think those patterns need to be applied at the language level to be really useful though.

Reactive Programming in an Object Oriented World

JavaScript has introduced the map/filter/reduce methods on arrays to allow collection operations using a sequenced composition of functions.

There’s one minor thing that JavaScript developers should note. In LINQ these operations are lazy iterables. The map/filter operations aren’t actually executed until an .each() starts iterating over them. This avoids having to create duplicates of the result in memory. It also means that the underlying array can change after we call filter and map. This is similar to “live” collections in the DOM. But they can also be infinite in length just like Mozilla’s Iterators. The .each() call is still essentially a synchronous operation though.

Erik Meijer and team simply decided to make that iteration execution asynchronous.

This means that the source data can be asynchronous. So instead of thinking of Events as independent, think of them as a stream of data with an unknown length… (or an asynchronous list/array).

This means that you can now apply the same type of function composition to streams of events. Enter the Reactive Extensions for .NET.

Supposedly this could solve the problem of Event composition in the UI space.

The Reactive Extensions for JavaScript

To my surprise, Matthew Podwysocki recently started a blog series about the Reactive Extensions for JavaScript (also Microsoft to be clear). Apparently the benefits of this tool in the JS world has not gone unnoticed.

There are no bits officially released yet. However, considering Matthew Podwysocki’s recent posts and Eric Meijer’s upcoming talk at the Mix conference… I wouldn’t be surprised if something was released at Mix on March 17th.

Learning More

I have since been interested in learning more about various alternative models. There’s a research project called Arrows which provides a different model that’s more purely functional. There’s also a framework called Flapjax which is more of a DOM library aiming to provide reactive concepts to JavaScript.

To learn more about the Reactive Extensions, take a look at the videos about the .NET version posted by the team over at Channel 9.

Concerns

I’m not sure the first implementation of the Reactive Extensions is going to be the one to solve all these problems.

I think that many developers will have a difficult time thinking about these concepts in the terms of event streams. That could make it difficult to use the current method naming. In this sense, I think Arrows might be easier to get started with. It will allow you to think about events as sequential operations. However, I also see benefit in the model employed by the Reactive Extensions, IF we can all wrap our heads around it.

Another issue is the “Let” method. This may be difficult to know when to use for many developers. That’s true even for LINQ. However, in the Reactive Extensions I have a feeling those issues will become even more prevalent. Hopefully there will be better syntactical sugar to solve this issue.

Rx has yet to prove itself in real world complex applications that goes well beyond single subscription examples. I may try to extend the canonical drag and drop examples to my own HTML5 based Drag and Drop model and plugins to stress test it.

Naming Conventions

There’s also the issue of upper camel case in method names. LINQ for JavaScript is also using this convention. I’m guessing they’re trying to be compatible. However, the JavaScript convention is to use lower camel case method names, which also the new ASP.NET AJAX library is doing. So I don’t understand why.

In dynamic languages with limited auto-completion (IntelliSense) support, naming conventions are very important to follow.

Although, I do like the names Select/Where/OrderBy better than map/filter/sort since given the arguments, that tends to read better as a grammatical sentence.

UPDATE: Event DSLs

I should mention that the MooTools 2.0 team has been working on a DSL based on the CSS selector syntax. This is an extension of the Element.Delegation plugin.

The idea is to use event names and pseudos in combination to create custom composite event listeners. This example would listen to the first click event:

element.addEvent('click:flash', firstClick);

This could enable a lot more powerful combinations of custom events. However, it doesn’t enable passing of parameters and the composability of Rx and Arrows.