Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Introduction to the Reactive Extensions for JavaScript – Composing Callbacks

So far in this series, we’ve covered some basic information about the Reactive Extensions for JavaScript (RxJS) including creating observables and creating observers as well as jQuery integration.  Now that we have a foundation in some of the basic building blocks, let’s actually do something interesting with it.  For example, how would we compose two AJAX calls together with callbacks?  In this post, we’ll explore using the Bing Translator in combination with jQuery and the RxJS.

Before we get started, let’s get caught up to where we are today:

Detecting and Translating Text with the Microsoft Translator

One of the many examples I’ve played with involving asynchronous programming, especially with my F# samples as well as the Reactive Extensions for .NET is using the Microsoft Translator.  This API, which is provided in several flavors (SOAP, AJAX and HTTP) allows us to not only translate but also detect the language of a given piece of text.  Just as well, there are other functions such as getting all languages codes and getting all language names by language code, and we’ll cover that in a subsequent post.  Getting started, you need to apply for a developer key which you can get here.  From there, we can embed our JavaScript link in our HTML so that we can get started.

<script type="text/javascript"
        src="http://api.microsofttranslator.com/V1/Ajax.svc/Embed?appId=myAppId">
</script>

In this example, we’re going to first detect the language of the given piece of text and then translate it into another language.  In honor of Erik and his team, I decided on Dutch as the destination language.  In order to detect the language we need to call the detect function which looks like the following.  It takes in some text and then a callback which then will give us our result as the function parameter.

Microsoft.Translator.detect(
    text,      // Text of the unknown language 
    callback); // A callback on complete

Next, we need the ability to translate our text to Dutch once we’ve determined the source language.  In order to do so, we must call the aptly named translate function which we provide our text, a from language that we’ll provide from our detect function callback, our destination language and finally a callback which provides us with the resulting text.

Microsoft.Translator.translate(
    text,      // Text to translate 
    from,      // The source language
    to,        // The destination language
    callback); // The handling callback

What you’ve noticed from these two functions is that they provide callback functions for each.  If we want truly compositional behavior, our code could get quite messy especially if we’re doing anything such as filtering results, transforming, aggregating and so forth.  But for now, we’ll have a simple example of composing these callbacks together.  In order to do so, we have to turn these two functions, detect and translate into Observables.  So, how do we do that? 

In this case, we’ll make use of the AsyncSubject class which allows us to represent the result of an asynchronous operation.  This class will take one value and only one value and then caches it for all future calls and acts as both an Observer and an Observable.  So for each time we call this subsequently, it will not cause a side effect and instead yield us the cached calculated value.  We’ll then call the detect method with our text and a callback, and inside of our callback, we’ll yield the value with OnNext and then mark our sequence as completed by calling OnCompleted.  Finally, we’ll return our AsyncSubject as an Observable and hide the fact that it’s both an Observer and Observable.

function detect(text) {
    var subject = new Rx.AsyncSubject();

    Microsoft.Translator.detect(
        text,
        function(result) {
            subject.OnNext(result);
            subject.OnCompleted();
    });

    return subject.AsObservable();
}

The same also applies to our translate function in pretty much the same form as we have above.

function translate(text, from, to) {
    var subject = new Rx.AsyncSubject();

    Microsoft.Translator.translate(
        text,
        from,
        to,
        function(translation) {
            subject.OnNext(translation);
            subject.OnCompleted();
    });

    return subject.AsObservable();
}

Now, let’s compose these together in such a way that we first detect the language of the text and then translate.  To make that happen, we’ll use the SelectMany method which projects each value of our observable sequence to an observable sequence and flattens the resulting observable sequences into one observable sequence.  In this case, we’re only projecting one value to the next observable sequence.

var translator = detect(translateText)
    .SelectMany(function(detected) {
        return translate(translateText, detected, "nl");
    });

Of course we could do more like filter, scan, etc with this, but it’s a good start.  Now bringing it all together in a jQuery and RxJS way, we can now complete our example by wiring up our HTML to take the input from a textbox once a button has been clicked, translate it, and display the result.

$(document).ready(function() {
    $("#translateCommand")
        .ToObservable("click")
        .Subscribe(function(event) {

        var translateText = $("#translateText").val();
        var translator = detect(translateText)
            .SelectMany(function(detected) {
                return translate(translateText, detected, "nl");
            });

        translator.Subscribe(function(translated) {
            $("#translatedText").html(translated);
        });
    });
});

And now we can see it in action by entering a sentence and sure enough it detects it as English properly.

image

How can I be sure of that?  What if I want to perform a side effect during the process, such as displaying our detected language?  To do that, we can use the Do method which invokes some sort of action for its side effect for each item in the sequence.  We could then change our translator Observable to the following to enable that behavior.

var translator = detect(translatedText)
    .Do(function(detected) {
        $("#detectedText").html("Detected " + detected);
    })
    .SelectMany(function(detected) {
        return translate(translatedText, detected, "nl");
    });

Now we have a nice compositional and quite fluent chain which deals with asynchronous behavior.  Invoking it this time in Spanish, we get the following result.

image

We could go even further to aggregate counts of which language was detected over time by using the Scan function, but that’s for another time.

Conclusion

Through the use of the Reactive Extensions for JavaScript, we’re able to bring compositional behavior to that which had been harder to do, such as asynchronous callbacks.  We’re able to get code in a nice fluent manner that makes sense and let’s us focus on the core problem domain instead of scattering code within a bunch of callbacks which can lead to any number of race conditions.

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 (who you can now follow on Twitter).  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.

This entry was posted in Event-based Porgramming, JavaScript, JSConf, Reactive Framework. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @Demis,

    Ok, let’s look at your questions each one at a time.

    To think about why we’d use a SelectMany over Select is the following:

    Remember, the signature of each, IObservable and IObservable. To do that by default, you use a SelectMany, even if the observable sequence only yields a single value, else you use a Select and Switch which I’ve covered before.

    Now think your solution of using Select through here. If I want to transform one observable sequence to another, using Select…

    // IObservable -> (T -> IObservable) -> IObservable>
    someOperation.Select(x => someOtherOperation(x))

    The problem with that approach is that unless you have a Switch statement to return that single value, you now took a IObservable and turned it into an IObservable>. The Select and Switch is the same intent of the SelectMany with a single value.

    The reason why I broke the Do into a separate step is the separation of concerns that I have. I want my Do to only do one thing and I want my SelectMany to have the same intent, one thing. To think about programming in Rx, we think about small composable steps.

    Matt

  • http://www.servicestack.net/mythz_blog/ Demis Bellot

    “To make that happen, we’ll use the SelectMany method which projects each value of our observable sequence to an observable sequence and flattens the resulting observable sequences into one observable sequence. In this case, we’re only projecting one value to the next observable sequence.”

    I think its sentences like the above that is hindering readability of an otherwise good series. Rx is a very nice succinct API but in order to take advantage of it I’m going to need a better idea of ‘why’ I need to do something.

    With the above example I’m still not sure why we have to use ‘SelectMany’ since as far as I can tell where only producing 1-click => 1 detect language => 1 translate text. Given the previous assumption what would the effect be if we didn’t use ‘SelectMany’?

    Also I’m lost as to why you need a separate ‘Do’ method chain when it looks like you could quite easily merge the:

    >$(“#detectedText”).html(“Detected ” + detected);

    In the ‘SelectMany’ method body? Again its more code to write and not obvious why we have to write it. I think having more code examples is definitely going to help.

  • http://www.javascriptbank.com/ JavascriptBank.com

    very cool & good tip, thank you very much for sharing