1

I am trying to be a good jQuery citizen, and embrace promises, but some basic usage still escapes me.

The code below is a panel loading method, that may receive a request to redirect to another page instead of load the original one specified. The redirect is under sever control (e.g. based on previous user response).

private _loadNewPanel(url: string, data?: any): JQueryPromise<any>
{
    var THIS = this;
    var dfd = $.Deferred();
    var promise = dfd.promise();

    $.ajax({
        cache: false,
        url: url,
        type: data ? "POST" : "GET",
        data: data
    })
        .done((html: string, textStatus: string, jqXHR: JQueryXHR) =>
        {
            var location = jqXHR.getResponseHeader('redirect-url');
            // Server says to redirect
            if (location)
            {
                // Chain to the new load request
       // **** WHAT TO DO HERE WITH RETURNED PROMISE ***
                THIS._loadNewPanel(location, null);
            }
            else
            {
                dfd.resolve(html);
            }
        }).fail((jqXHR, textStatus: string, errorThrown: string) =>
        {
            dfd.reject(errorThrown + ": " + url);
        });

    return promise;
}

Is it a case of simply adding .done() to the recursive call like this and pass back the results?

       // Chain to the new load request
       THIS._loadNewPanel(location, null).done(function(html){
             dfd.resolve(html);
       }).fail(function(error: string){
             dfd.reject(error);
       });

Is there a sleeker way of writing the whole thing? Am I abusing jQuery promises?

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202

1 Answers1

1

Yes, there is a slicker way of writing the whole thing. $.ajax already uses promises.

In order to use the promise it returns, simply return it:

 THIS._loadNewPanel(location, null).done(function(html){
         dfd.resolve(html);
 }).fail(function(error: string){
         dfd.reject(error);
 });

Can simply be:

 return THIS._loadNewPanel(location, null); // why is THIS uppercase here :P? 

Similarly in the above code. You only need deferreds at the absolute lowest level of your API and only if the API doesn't support errors in the first place. In fact what you did is called the deferred anti pattern.

If you want to chain the response, you can use .then:

var req = $.ajax({...}).then(function(resp){
      var location = req.getResponseHeader("redirect-url");
      if(location) return THIS._loadNewPanel(location, null); // NOTE THE RETURN
      return resp;
});
return req;
Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • How can I return the promise when I do not know if I need to load the second page until *after* the first async ajax call has completed? PS. `THIS` is uppercase as it is the usual `var that = this` instance (but my own standard). – iCollect.it Ltd Jul 17 '14 at 16:38
  • @TrueBlueAussie you can return promises from `.then` handlers of previous promises. I've added a sample - also check the linked question. – Benjamin Gruenbaum Jul 17 '14 at 16:39
  • cool.. Will give it a try tomorrow (heading home now). Thanks – iCollect.it Ltd Jul 17 '14 at 16:39
  • @TrueBlueAussie: This chaining is the [entire point of promises](http://stackoverflow.com/a/22562045/1048572) :-) – Bergi Jul 18 '14 at 08:17