Using DeftJS Promises to Simplify Service Interaction

The DeftJS framework for ExtJS and Sencha Touch has been updated to include a Promise API. John and I are already at work on updated docs that cover these (and other) new features, but I wanted to post an entry to explain some of the benefits that Promises bring to the table.

If you aren’t familiar with Promises, perhaps the Wikipedia definition will help:

In computer science, future, promise, and delay refer to constructs used for synchronizing in some concurrent programming languages. They describe an object that acts as a proxy for a result that is initially unknown, usually because the computation of its value is yet incomplete. 

Put another way, a Promise represents a future value that will eventually be returned asynchronously. In the JavaScript world, the folks at CommonJS have proposed a specification called Promises/A, which is what the DeftJS Promise API is modeled upon.

Definitions are nice, but I find examples to be much more useful to aid in understanding something. So lets jump in and look at some code.

A Common Example of an Asynchronous Call in ExtJS

Say I’m building an ExtJS application that uses DeftJS. I’ve tried to separate my concerns, so I’ve created a ViewController to manage a UI component, and a Service class to encapsulate interaction with some of my Stores, AJAX logic, and external resources. My ViewController might have a loadCompanies() method like this, which calls an injected Service object. The Service, in turn, asks a CompanyStore to load its data:

“OK,” you might think, “that doesn’t look too bad.” And on the surface, it isn’t too bad. But let’s dig further. Stores aren’t the only option ExtJS provides for leveraging AJAX. It also has an Ajax class which can be used when a Store won’t fit your needs, or when you need more control over the handling of the results. Let’s look at the same general process I showed above, but using the Ajax class:

Notice anything disconcerting? The two calls to my Service method have different ways of defining the callbacks: one passes a “callback” property, but the other passes separate “success” and “failure” callbacks. The code in the controller is coupled to the way the service loads data. Worse, if you have a number of these sorts of service calls, with mixed sets of arguments, things get pretty ugly. Luckily, using a Promise offers a better way.

An Asynchronous Call using a Promise

Here is the ViewController code, along with examples of Service methods using both a Store load and an AJAX request:

Excellent. Now the ViewController method looks exactly the same, regardless of what the Service is doing! The Service methods create a Deferred object to wrap the async call, and then return a Promise back to the ViewController. Also, note that I can use the always() method provided by the Promise to run code regardless of whether it succeeded or failed. So what’s the difference between a Deferred and a Promise? To help explain the difference, I created this simple diagram:

So the general idea is that the Deferred is “private”, and actually wraps the async call. The Promise is the “public” view of the state of the Deferred. It won’t allow you to resolve or reject its state, but it will allow you to attach callbacks that are invoked when the state of the Deferred changes.

Multiple Asynchronous Calls

So we’ve seen how a Promise can help standardize the way things interact with async processes, and that’s great. But Promises can do a lot more. For example, let’s say at app startup I need to load both a list of companies and a list of featured products. I can’t proceed until both are finished. One way (a very bad way) this could be done is:

I think we can all agree that’s just horrible. There are actually some slightly less horrible ways that could be done, but any way you slice it, it’s not very pretty. So how can using Promises help? How about:

As you can see, I’m taking the two Promises returned by loadCompanies() and loadFeaturedProducts(), and wrapping them in another Promise. That Promise will resolve or reject based on the state of the two Promises it is wrapping. Even better, we can once again see that the code in the ViewController stays exactly the same as in the previous examples! This is a far better option than the other hackish ways one might come up with to execute multiple calls in a single group.

Conclusion

I’ve shown how Promises can bring consistency to code that has to deal with asynchronous behavior. The ability to treat multiple asynchronous calls as a single unit just adds more icing to the cake. Promises are useful in even more ways, but I’ll stop rambling for now. If you use ExtJS and are using (or considering) DeftJS, you’ll definitely want to give the Promises API a try.

 

Brian has been developing web applications for over 14 years, primarily using Java, Groovy, .NET, ColdFusion, ExtJS, Flex, and AIR. He's worked as a consultant or employee on a wide range of projects for private companies and government agencies. Brian is a regular speaker at industry conferences, as well as a blogger and author. He has contributed to a number of community endeavors, including DeftJS, Swiz, Fusebox, ColdSpring, and several RIAForge projects.

Tagged with: , ,
Posted in HTML RIA Development, Life After Flex
5 comments on “Using DeftJS Promises to Simplify Service Interaction
  1. Gareth Arch says:

    Thanks for the write up of this stuff.

    Didn’t realize it was written in coffeescript at first, so I was looking at the “@” and “->” and figured I was missing something being still slightly new to Sencha.

  2. Brian Kotek says:

    Sorry, guess I assumed that with all my droning on about CoffeeScript in prior entries that I should stop talking about it heh. I’ll try to make sure I mention that the code is in CS in the future just to make sure it’s not confusing. Thanks.

  3. Gabrielle says:

    Thanks a lot Brian. Your post sheds light on DeftJS Promises.
    Keep doing such “tutorials”. It is much appreciated.

  4. Thomas says:

    I don’t know if I’m missing something, but I’m trying to do something similar to your loadInitialData example, except instead of loading a store I’m just doing a regular ajax request. I’m doing pretty much the same thing, except where you have store.load() I’m doing Ext.Ajax.request() and in the success callback there I’m doing deferred.resolve(). Everything appears to work fine when the requests are successful, but to test a failure I removed one of my deferred.resolve() calls and the success() function in the then() still runs. I also tried called deferred.reject(), also doesn’t work, the success() function still runs. Am I missing something?

  5. Hmm, it sounds to me like you could be doing

    Ext.Ajax.request({
    ….

    success: deferred.resolve()
    ..
    }

    instead of

    Ext.Ajax.request({
    ….

    success: deferred.resolve
    ..
    }

    in which case deferred.resolve() is going to run every single time regardless of whether the success event triggers or not.

    Probably worth posting the code you have.