0

Using jQuery promises I do the following to manage a situation where I have multiple instances where I need to call for external resource, but I don't want to call for the same external resource more than once.

  1. Initital REST calls gets me multiple data objects with references to additional information (in the example "department" property gives a reference to where I can find more info about the department).

{ "somedata": "...", "department": "https://api.../departments/1000", }

  1. Already deep down in separate function calls for each data object I wish to coordinate all calls to the same resources. I don't want to fetch department name for "department 1000" multiple times.

  2. I save promises OR a returned result in a dictionary and reuse them.

    a. If it is a promise, I return the same promise to be reused by the caller.

    b. If it is a fetched value, I resolve the promise asynchronous by using a timeout.

Here is the code:

var Departments = {};

function getDepartmentName(id){
   var dfd = new $.Deferred();
   var promise = dfd.promise();

   if(id in Departments){
        if(typeof Departments[id] == 'object'){
            return Departments[id];//reuse the promise
        }else{//department name is a string
            setTimeout(function(){ dfd.resolve(Departments[id]); }, 0);         
        }
   }

   else{
       Departments[id] = promise;//Set dictionary value to the promise
       var dPromise = FetchDepartment('https://api.../departments/'+id);
       $.when(dPromise).then(
           function(departmentName){
               Departments[id] = departmentName;//Re-set dictionary value to the fetched value
               dfd.resolve(departmentName);
           },
           function(err){
               delete Departments[id]; 
               dfd.reject('Call failed');
           }
       );   
   }
   return promise;

}

It seems to work but I am concerned whether this is such a great design. I have a few questions.

  1. Is there some promise functionality I should use instead?
  2. Are there any situations where things might happen in the wrong order?
  3. Is it correct to reuse a promise instance like this? Multiple callers make a call to .then of the same promise object, and it seems to work well, but I don't know how jQuery chain all these recipients when the promise is resolved.
Gil Roitto
  • 325
  • 2
  • 8

1 Answers1

1

I save promises OR a returned result in a dictionary and reuse them. If it is a fetched value, I resolve the promise asynchronous by using a timeout.

Don't make it so complicated. This behaves exactly the same as if you just kept the promise and only returned it, instead of creating new promises for calls after the initial one fulfilled.

Also, avoid deferreds when you are already dealing with promises.

var Departments = {};

function getDepartmentName(id) {
    if (id in Departments){
        return Departments[id]; //reuse the promise
    } else {
       var promise = FetchDepartment('https://api.../departments/'+id).then(null, function(err){
            delete Departments[id]; // allow retries
            throw err;
        });   
        return Departments[id] = promise;
    }
}

Is it correct to reuse a promise instance like this, where multiple callers make a call to .then of the same promise object?

Yes, this is totally fine. Their callbacks will be scheduled in the same order as the originating calls to then.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    Aha, I see. Since [then callback will get called immediately in this case if then was called after promise has already resolved](https://stackoverflow.com/questions/32059531/what-happens-if-a-promise-completes-before-then-is-called) I don't need to save away the value for reuse, I can just save the promise consistently. Greatly appreciated and very well explained. Thank you! – Gil Roitto Jul 25 '18 at 08:41