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!

Dojo Deferred and the Reactive Extensions for JavaScript

We’ve covered quite a bit in this series including how well the Reactive Extensions for JavaScript plays with other libraries and what integration points we have.  Our main thrust in providing this is that we don’t want to replace your library of choice, whether it be jQuery, Dojo, MooTools, YUI in addition to the server components of node.js.  Instead, we want to build bridges from them when you encounter the pains of asynchronous and event-based composition which frequently crop up in JavaScript applications both on the web and even on the server.  Case in point, let’s go over our latest integration with the Dojo Toolkit’s promises via the dojo.Deferred module.

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

 

Dojo Deferred

The Dojo dojo.Deferred module is a central piece of the Dojo Toolkit which serves as the basis for such things as AJAX calls like xhrGet among others.  At its core, it serves as a promises API which acts as a proxy for value which has not yet been calculated, and through this API, we have a clear separation of concerns which allows us to abstract the asynchronous behavior via callbacks into the promise itself, instead of the method signature.  The same could be said of the Reactive Extensions for JavaScript as well. 

Although dojo.Deferred has been around for a while, the newest release of the Dojo Toolkit has added another method to handle both the success and failure cases of a given computation, such as the following code.  Imagine we had an asynchronous function which returns to us a dojo.Deferred object, which does nothing more than delay by a second and return the value.

function someDeferredFunction() {
    var deferred = new dojo.Deferred();
    setTimeout(
        function() {
            deferred.callback(42); 
        }, 1000);
    return deferred;    
}

Then we can subscribe to both its success and failure cases by using the then function.

var deferred1 = someDeferredFunction();
deferred1.then(
    // Success
    function(value) {
        alert(value);
    },
    // Failure
    function(error) {
        alert(error);
    });

We can see a bit of overlap between the ideas here and the heart of the Reactive Extensions for JavaScript.  The difference between the two is that this API treats asynchronous calls as one shot resumable methods whereas RxJS treats these as observable sequences.  So, how could we take advantage of this API and build a bridge between the two libraries?

From Deferred to Observable

The first order of business is to see how we can take a given dojo.Deferred and turn it into an Observable sequence yielding a single value.   Using the Reactive Extensions for JavaScript with the Dojo support added via the “rx.dojo.js” script, we can seamless leap between the two by calling the asObservable prototype method we added.

var deferred2 = someDeferredFunction();
deferred2.asObservable()
    .Select(function(value) { return value * value; })
    .Subscribe(
        function(value) {
            alert(value);
        });

In this example, we took the someDeferredFunction from above and then called the asObservable method, then we’re free to do such things as projections via Select in which we square the returned value and then subscribe to the result via Subscribe.  To show you how we did it, let’s walk through the code below.  First, we create an AsyncSubject which represents and asynchronous operation which accepts only one value and then caches it for all future observations.  Then we can call the then function and in the success case, we call OnNext with the result and OnCompleted to indicate we are finished, and in the failure case, we send the error on via OnError.  FInally we return the subject, thus completing our bridge.

dojo.Deferred.prototype.asObservable = function () {
    var subject = new Rx.AsyncSubject();
    
    this.then(
        // Success
        function (value) {
            subject.OnNext(value);
            subject.OnCompleted();
        },
        // Failure
        function (error) {
            subject.OnError(error);
        });
        
    return subject;
};

But, what about the other way around?  Can we go from an Observable sequence to a dojo.Deferred?

From Observable to Deferred

Because we feel like building bridges, we want to give the ability for traffic to go both ways.  For example, we could have a given AsyncSubject that we want to use with our existing Dojo functionality.  Imagine we had an Observable sequence that waits for a second and then yields the value via an AsyncSubject.

function someAsyncSubjectFunction() {
    var subject = new Rx.AsyncSubject();
    
    setTimeout(
        function() {
            subject.OnNext(42);
            subject.OnCompleted();
        },
        1000);
        
    return subject;
}

Now, we might have some processing logic written in Dojo, so we want you to take full advantage of that.  Via the AsDeferred method provided to us through the “rx.dojo.js” script, we build that bridge between the two libraries.  After calling AsDeferred, we can then use it as a regular dojo.Deferred object.  So, now we can call then passing in the two continuations for the success and failure cases.

var subject = someAsyncSubjectFunction();
subject
    .AsDeferred()
    .then(
        function (value) {
            alert(value);
        },
        function (error) {
            alert(error);
        });

Now, how did we make this happen?  We’ll need to extend the AsyncSubject with our AsDeferred method.  Inside, we’ll create a new dojo.Deferred which will handle the values from our AsyncSubject.  Next, we’ll subscribe to our subject via the Subscribe method, calling the callback method with our result on success, and errback on the failure.  Finally, we return the deferred which completes our bridge.

Rx.AsyncSubject.prototype.AsDeferred = function () {
   var deferred = new dojo.Deferred();
   
    this.Subscribe(
        function (value) {
            deferred.callback(value);
        },
        function (error) {
            deferred.errback(error);
        });
        
    return deferred;
}

And there you have it, our bridge between the Dojo Toolkit and the Reactive Extensions for JavaScript, which allows you to have the best of both worlds.

Conclusion

Dealing with asynchronous programming has been in the forefront of many minds in the JavaScript community.  At JSConf, there were several examples of frameworks trying to get around the idea of callbacks and instead lean more towards composition.  By utilizing the Reactive Extensions for JavaScript, we’re able to compose together asynchronous and event-based operations together and transform the results in interesting ways.

The Reactive Extensions isn’t meant to be the only solution in your toolkit, but instead you can continue to use the JavaScript library of your choice, and when you run into callback hell and composition issues, that’s where RxJS shines.  To that end, we’ve provided a lot of bridges between various libraries such as the following, and more to come:

So with that, download it, and give the team feedback!

This entry was posted in JavaScript, JSConf, Reactive Framework. Bookmark the permalink. Follow any comments here with the RSS feed for this post.