Moving from SPServices to Rest, Part 5: Using Promises with SOAP and REST
- Moving from SPServices to REST, Part 1: Introduction
- Moving from SPServices to REST, Part 2: New Patterns for SPServices Development
- Moving from SPServices to REST, Part 3: JSON vs. XML
- Moving from SPServices to REST, Part 4: Converting GetListItems to REST
- Moving from SPServices to Rest, Part 5: Using Promises with SOAP and REST
- Moving from SPServices to REST, Part 6: Converting UpdateListItems to REST
Wouldn’t it be great if we could drive flying cars like the DeLorean in Back to the Future? Unfortunately, even though October 21, 2015 has passed us by, that’s not a reality yet. The science fiction writer Arthur C. Clarke famously said, “Any sufficiently advanced technology is indistinguishable from magic.” Sometimes JavaScript promises can feel a little bit like magic – at least until you get good at working with them.
What are promises?
Both SOAP calls using SPServices and REST calls return promises. This is the case primarily because we are usually using a similar transport mechanism: maybe jQuery’s .ajax() function, which sends HTTP requests. (We don’t have to use jQuery, but it’s one of the more commonly used libraries to do this sort of thing. If you’re using one of the alternatives, you’ll need to do a little translation here.)
Promises are very cool mechanisms that work something like this. I think of it as a bit of magic, maybe like an act on America’s Got Talent.
When you make a call to SPServices or REST, you can assign the result of that call to a variable. That variable is a promise, which is sort of like an empty envelope. There’s no data in it when you first get it, but the call you just made promises to fill up the envelope for you. When the data is available and any conversion is finished, the original call sort of taps you on the shoulder and says, “You’ve got data!” (Say that in your best AOL voice.) At that point, you can start to do whatever work you want to do with the data.
Pretty neat, right? But, why does it matter? Well, when you are making AJAX calls, it can take a while for the server to respond. Servers are usually very powerful but they can get busy, or you may have asked for something complicated, or you may have asked for a lot of data, or the server may simply be tuned very badly. In any of those cases there will be a delay between the time you make the request and the time the response is available to you. The delay may be a few milliseconds or even a minute or two (though that probably indicates a poorly thought out request or a badly tuned server). During the time that delay occurs, you don’t want your JavaScript code to sit there waiting. Instead, you want to handle the call asynchronously meaning you don’t wait for it to finish; you elect to be notified when it finishes. That’s where promises come in.
Each browser reacts slightly differently to synchronous calls. Internet Explorer is probably the worst of the bunch, as it really hangs up until the request is complete. This makes for an unpleasant user experience, which ought never to be our goal. Because of this, using a promises pattern is important to ensure that your application feels responsive and peppy to your users.
What does converting to the promises pattern get us?
If you’ve been using SPServices for a long time, you may be setting async: false in many or all of your calls. This means you are making the calls synchronously, hanging up the browser. By moving to the promises pattern while still using SPServices, you’ll be setting yourself up for making REST calls efficiently down the road.
Let’s look at a simple example where we are just retrieving some items from a Custom List.
$().SPServices({ operation: "GetListItems", async: false, listName: "MyCustomList", completefunc: function(xData,status) { $(xData.responseXML).SPFilterNode("z:row").each(function() { // Process the data }); } });
In this example, a SOAP payload will be sent to the server, and our code will sit and wait until the response comes back because we have specified async: false. If we’re only making this one call on page load and there isn’t a lot of data coming back, that might be fine, as the response will come back quickly, so the user may not even notice.
But if the server is busy or we’ve asked for a lot of data, our user will be wondering why the browser is locked up. To avoid this, let’s switch to using a promise.
var p = $().SPServices({ operation: "GetListItems", listName: "MyCustomList" }); p.done(function() { $(p.responseXML).SPFilterNode("z:row").each(function() { // Process the data }); });
Here we’ve switched things around. We make the call to get the data, obtain the promise from the call and put it in variable p and then move on. Below the call, we have p.done(…), which means “When the response is here and ready to process…” Our JavaScript keeps executing from there and the browser is available to the user in the meantime. They might leave the page, click on some other actions, whatever.
When the promise is fulfilled, our code in the p.done(…) block executes. Now this will feel pretty weird to you until you get the hang of it. In the interim since you made the call, the DOM may have changed and the user may have done other things. You need to take those possibilities into account as you process the data you’ve received in the response.
Why convert now?
Converting to the promises pattern while you still are using SPServices to make SOAP calls has some advantages.
First, you already know how your code works. It may have taken you a while to get it up and running. As you’re thinking about how to move from SOAP to REST, you may not want to change too many things at once.
Find a simple call using SPServices and convert it to the promises model so that you understand how it works. Your user experience will improve even if you don’t move to REST yet. Even better, you can make this change in SharePoint 2007 or 2010 without having to switch to REST at all.
By the way, the call above in REST would look something like:
$.ajax({ url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('MyCustomList')/items", method: "GET", headers: { "Accept": "application/json; odata=verbose" }, success: function(data) { success(data); // If the call is successful, process the response }, error: function(data) { failure(data); // Do something with the error } });
The success and failure functions will only be called once the promise from the $.ajax function is resolved, so it’s somewhat equivalent to the promise-based call using SPServices above.
Conclusion
Since one of my goals in this series is to make moving from SOAP to REST less painful, I want to give you smaller steps you can take to get there without hurting yourself. Moving to the promises pattern now – whether you decide to go fully to REST or not – will put you in a better place when you do decide to take the plunge. Even better, it will prepare you for more “modern” Web development down the road, where you may be consuming data from multiple services. Those services may all be within SharePoint Online or Office 365 or they may be from separate sources altogether. Many of those services will be exposed via REST and the promises pattern will enable you to manage all of that data flying around more effectively.