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 – From Blocking to Async

We’ve covered a bit of ground already in this series on the Reactive Extensions for JavaScript (RxJS) from the basic information, creating observers and observables, jQuery integration and in the last post talking about composing asynchronous methods with callbacks.  Now that we have some more fundamental building blocks, let’s see what else we can do with it.  Since we talked about asynchronous methods last time and making them composable, how about this time taking a method that is seemingly a blocking AJAX call and turn it into an asynchronous method?  In this post, we’ll finish up the Microsoft Translator example by playing with the getLanguages and getLanguageNames methods and see what we can do with them.

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

From Synchronous to Asynchronous

Just like before we’re going to use 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 part today.  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, our ultimate goal is to merge together the language codes with the language names that are localized to Dutch, once again in honor of Erik Meijer in his team.  In order to get all the language codes, we need to make use of the getLanguages function which returns to us a string array of said codes. 

string[] Microsoft.Translator.getLanguages();

Next up, we need to be able to get the language names localized based upon a language code.  To do that, we’ll call the getLanguageNames function which has the following signature.

string[] Microsoft.Translator.getLanguageNames(
    locale); // Language code to localize language name

We already covered how we can take existing arrays and convert them to an observable sequence by using the Observable.ToArray method.  Let’s make that call a little cleaner by extending the Array prototype to include a toObservable function.

Array.prototype.toObservable = function() {
    return Rx.Observable.FromArray(this);
};

Now this gives us some nice syntax to turn any given array to an observable such as the following:

[1,2,3]
    .toObservable()
    .Select(function(x) { return x * x; })
    .Where(function(x) { return x % 3 == 0; })
    .Subscribe(function(x) { alert(x); });

And in the case of our getLanguages function we could do this:

function getLanguages() {
    return Microsoft.Translator.getLanguages().toObservable();
}

But in this case, it would be a blocking call to first get the array and then to turn it into an Observable.  Instead, we want to kick off the call to the getLanguages asynchronously.  We could use the ToAsync method…

// Returns IObservable<string[]>
function getLanguages() {
    return Rx.Observable.ToAsync(
        function() { Microsoft.Translator.getLanguages(); });
}

Unfortunately this wouldn’t work as it would yield, in C# parlance, an IObservable<string[]> which is certainly not what we want as we want each string to be given asynchronously.  So, how else could we do this?

We can achieve that with the Start function which takes no arguments and you return what you want to yield.  In this case, we’ll yield our getLanguages observable sequence which contains all of our language codes.  What this would give us, in C# parlance, is IObservable<IObservable<string>>, but what we want is just an IObservable<string>, and in order to make that happen, we must call the MergeObservable function which merges an observable sequence of observable sequences into an observable sequence.  Below is what the code should look like for taking our getLanguages and making it an asynchronous call.

function getLanguages() {
    return Rx.Observable.Start(function() {
        return Microsoft.Translator.getLanguages().toObservable();
    }).MergeObservable();
}

The same logic once again can apply to the getLanguageNames function as well yielding the following function:

function getLanguageNames(locale) {
    return Rx.Observable.Start(function() {
        return Microsoft.Translator.getLanguageNames(locale).toObservable();
    }).MergeObservable();
}

Now that we have both of our functions to be asynchronous, let’s merge these two together to list the language code with the localized language name (in Dutch of course).  To merge these two into one, we’ll use the standard Zip LINQ operator, which is new in .NET 4.0 as well as RxJS, which looks something like the following in pseudo code.

var observable = {
    ...
    function Zip(
        right,     // Right hand collection 
        selector); // Combining function
};

In this case of using the Zip, we’ll simply return an object with two properties, a locale and a language and then on the subscription, we’ll just append items to an unordered list.

$(document).ready(function() {

    getLanguages()
        .Zip(getLanguageNames("nl"), function(locale, language) {    
        return { locale : locale, language : language };
    }).Subscribe(function (result) {
        $("#languageNames")
            .append("<li>"+result.locale+" - "+result.language+"</li>");
    });

});

And that yields the following result:

image

So, there you have it, a case of turning a pretty interesting blocking call string array and turning it into an asynchronous observable sequence of strings.

Conclusion

Through the use of the Reactive Extensions for JavaScript, we’re able to take blocking calls such as our AJAX calls here and turn them into asynchronous observable sequences.  Through such methods as Start, or ToAsync, we’re able to take calls that are potentially expensive and have them run in a non-blocking fashion.  Next time, we’ll move onto taking examples in FlapJax and converting them into Rx to show how that might work.

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.
  • A anand

    can i implement this in javascript ??

  • Xiyuan

    thanks for sharing,

    i tried your sample code, it seems that Zip operation does not work correctly for me.

    getLanguages().Subscribe(function(locale){
    //
    }) works

    getLanguageNames(“nl”).Subscribe(function(language){
    //
    }) works

    but

    getLanguages().Zip(getLanguageNames(“nl”), function(locale,language){
    return {locale:locale, language:language};
    })).Subscribe(function(result){
    //
    }) does not work.

  • http://www.kms-technology.com Tran Le Vu Chi Lang

    I’ve tried your example many times. It seems that your example does not work well. Even if I keep pressing the mouse left button and move, it automatically stop moving.

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

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