Introduction to the Reactive Extensions for JavaScript – Creating Observables

In the previous post, we covered a little about the Reactive Framework (Rx) for JavaScript.  Since that time we’ve learned that Jeffrey Van Gogh will be attending the upcoming JSConf 2010 and hoping to bring along some Reactive Extensions for JavaScript for anyone who is interested.

Back to the subject at hand, let’s take a step back and look at what we’re trying to accomplish with Rx for JavaScript.  As we should know, the model of the web is largely asynchronous in that we shouldn’t block for potentially long running operations.  For example, we could have a large and potentially expensive collection to iterate through and process, which is in turn a blocking call.  What if we could instead turn from these pull collections to a push model?  What about going from a pull model or interactive design:

function processItems(items) {
    $.each(items, function(index, item) {
        // Do something like append
        $("#results").append("<li>" + item.name + "</li>");
    });
}

To more of the push model or reactive model:

function processItems(items) {
    items.Subscribe(function(item) {
        // Do something like append
        $("#results").append("<li>" + item.name + "</li>");
    });
}

Things such as events are perfect examples of reactive programming and a natural fit, but potentially any blocking call sequence could be as well.  Before we look into how we create them, let’s first look at the two big pieces, Observer and Observable.

Understanding Observer and Observable

The two main players, as they are in the Reactive Extensions for .NET are the Observer and Observable types.  Let’s first look at the Observer.  The relationship between the two is that the Observable is the producer of values, and we subscribe through an Observer where we can handle each value as they come along, as well as any potential exception, and when the Observable is complete.  Let’s first look at the Observer class in pseudo-code to show you what the signature looks like.  The Observer contains three methods, the OnNext, called when producing the next value in the sequence, the OnError which is called when an error is produced, and finally OnCompleted when the observable sequence has completed.

var Observer = {
    this.OnNext : function(next) { ... },
    this.OnError : function(exn) { ... },
    this.OnCompleted = function() { ... }
};

Next, let’s look at the Obsevable type which has any number of methods, but let’s cover the Subscribe which takes an Observer and invokes the appropriate methods such as OnNext for the next value, OnError for any errors that might come up and OnCompleted, when the sequence completes.

var Observable = {
    this.Subscribe : function(obs) { ... }
}

Now that we have a basic understanding of Observer and Observable, let’s go ahead and create some Observables.

Ways to Create Observables

We’ve covered briefly how to turn JavaScript HTML events into observables in the last post, but let’s dive deeper into how we create them not only from events, but from scratch as well.  We have many options at our disposal to do this, so we’ll cover each one  in turn.  One concern that was raised when I was first covering this is the testability.  After all, if I’m strictly tied to events such as mouse moves and other HTML events, then I’d agree about the testability, but luckily we’re not as we’ll see below.

Creating an Observable

First, we have the method Observable.Create which creates an observable sequence from the subscribe implementation.  This method takes a function with an Observer and returns a no parameter function which acts as the cleanup/Dispose.   In this simple example, I’ll yield one value and then complete.  Finally, I must return a function which is to serve as our cleanup which is to be run after we unsubscribe.

var observable = Rx.Observable.Create(function(obs) {
    obs.OnNext(3);
    obs.OnCompleted();

    return function() { };
});

Just as well, we can handle errors inside of this Create function to handle any exceptions that could arise.  In this simple example, I’ll throw an exception in the error block and then in the catch block, I will compensate by invoking the OnError compensation.

var observable = Rx.Observable.Create(function(obs) {
    try {
        throw "ahoy, an exception!";
    } catch(err) {
        obs.OnError("Arr! " + err);
        obs.OnCompleted();
    }

    return function() { };
});

Next, we have the CreateWithDisposable which has the same intent as Create, but instead of returning a function, we create an object with an object with a Dispose method.

var observable = Rx.Observable.CreateWithDisposable(function(obs) {
    obs.OnNext(3);
    obs.OnCompleted();

    return { Dispose : function() {} };
});

These are all well and good but there must be some other ways of creating observable sequences.

Yielding a Single Value with Return

Another way to create an observable to yield a single value is through the Return method.

var item = "Just one item";
var observable = Rx.Observable.Return(item);

Creating an Observable Sequence with Range

Just as we can return a single value, we can also return a range of numbers using the Range method.  This method has the same signature of its LINQ Enumerable counterpart with a start value and a count.

var rangedObservable = Rx.Observable.Range(1, 100);

Creating an Observable Sequence with Generate

A more flexible way of creating sequences than the Range method would be the Generate function.  This function takes an initial state, a conditional function, a result selector and finally an iterator.  To give a basic idea of how this works, let’s just go from 0 to 9 using the Generate function:

var observable = Rx.Observable.Generate(
    0,                                // initial state
    function(x) { return x < 10; },    // condition
    function(x) { return x; },        // selector
    function(x) { return x + 1});    // iterate

From Array to Observable

In addition to creating our observable sequences from scratch with the Create method, we can take existing arrays and go from the pull model to the push model by calling the FromArray method.  This in turn takes all values from our array and puts them into an observable sequence for us.

var items = ["one","two","three"];
var observable = Rx.Observable.FromArray(items);

This is also great for testing scenarios, to replace such things as mouse movements with a simple array for testability purposes.  Now, let’s move onto tackling events.

From HTML Events to Observables

We covered this in the first post a bit, but let’s revisit this again.  As you well know by your adventures in JavaScript and DOM land that there are quite a few events in the browser that we can take utilize.  Anything from mouse movements, keyboard presses to HTML forms, it covers the gamut as you can see from the list here.  Let’s take a standard mouse movement and go from an event to an observable sequence by using the FromDOMEvent method.  In order to create this event, we need a reference to our element of interest and a string naming the event we want to capture. 

var mainCanvas = document.getElementById("mainCanvas");
var observable = Rx.Observable.FromDOMEvent(mainCanvas, "mousemove");

Using jQuery, we can also get a hold of our element of interest by doing the following:

var mainCanvas = $("#mainCanvas").get(0);
var observable = Rx.Observable.FromDOMEvent(mainCanvas, "mousemove");

But, we’re not limited to just standard HTML events.  Internet Explorer also introduced a few custom events such as clipboard events and data binding, and some of which have been picked up by other browsers (and some not).  For example, we could attach to the cut event of a given text box element by using the FromIEEvent method:

var textElement = $("#textElement").get(0);
var observable = Rx.Observable.FromIEEvent(textElement, "oncut");

But, having to differentiate between the two can be kind of annoying, so how about a unifying concept to bring both sets together?  The FromHtmlEvent does just that by checking whether it is an IE event or a DOM event, so we needn’t worry about which is which.  We can now take the mouse move from above and use the FromHtmlEvent instead.

var mainCanvas = $("#mainCanvas").get(0);
var observable = Rx.Observable.FromHtmlEvent(mainCanvas, "mousemove");

Just as well, we could also take our IE specific event and call from HtmlEvent as well.  Note, however, that the event now must exclude the “on” prefix in order to make this work:

var textElement = $("#textElement").get(0);
var observable = Rx.Observable.FromHtmlEvent(textElement, "cut");

That’s plenty for now on how to get started creating observable sequences of your own.

Conclusion

This of course is only scratching the surface of what capabilities this library has and there is much more yet left to cover.  The question you’re probably asking now is where can I get it?  Well, for that you’ll have to stay tuned.  I hope to have more announcements soon about its general availability. 

What can I say?  I love JavaScript and very much looking forward to the upcoming JSConf 2010 here in Washington, DC where the Reactive Extensions for JavaScript will be shown in its full glory with Jeffrey Van Gogh.  For too many times, we’ve looked for the abstractions over the natural language of the web (HTML, CSS and JavaScript) and created monstrosities instead of embracing the web for what it is.  With libraries such as jQuery and indeed the Reactive Extensions for JavaScript gives us better tools for dealing with the troubled child that is DOM manipulation and especially events.

2 Comments

Comments have been disabled for this content.