Storable actions and promises

From the salesforce promise documentation:

Don’t Use Storable Actions in Promises

The framework stores the
response for storable actions in client-side cache. This stored
response can dramatically improve the performance of your app and
allow offline usage for devices that temporarily don’t have a network
connection. Storable actions are only suitable for read-only actions.

Storable actions might have their callbacks invoked more than once:
first with cached data, then with updated data from the server. The
multiple invocations don’t align well with promises, which are
expected to resolve or reject only once.

Should that deter me from using promises with the following use cases:

  1. I have to retrieve the current user information across multiple components before I allow a callback to the server.

  2. I also have to grab the entire role hierarchy to determine the roles above the user in order to determine the public group relationships from the group member table.

Both sets of this info would remain relatively static and would likely benefit from storable actions. If I do this across 4-5 components on the same app page, I think that would degrade performance, especially in the latter use case. How much of a hit would be taken from using a storable actions with promises, if any?

Answer

I’ve been thinking about this too as I’d like to build a reusable utility that can make metadata describe info available in Lightning. This falls under the “rarely changing info” category so it might be a place where it’s OK to mix storables and promises.

I’ve also been thinking though about what kind of patterns might be possible if you wanted to account for the second return. First off there is a way to know whether the callback is running a second time:

var action = cmp.get("c.myAction");
var firstTime = true;
action.setCallback(this, function(response) {
    if (firstTime){
        firstTime = false;
        // Do whatever logic is appropriate for first callback execution
    }
    else {
        // Do whatever logic is appropriate for second callback execution
    }
};
$A.enqueueAction(action);

But now what do you do when you want to connect that to a Promise? What we need is a way to signal “Do this when a response comes back, but also do this other thing when a second response comes back, if it does.”

So I have no idea if someone can come up with a better architecture but here is my thought:

executeAction: function (cmp, action) {
    var p1,p2,resolve2,reject2;
    var firstTime = true;

    p2 = new Promise(function(resolve, reject){
        resolve2 = resolve;
        reject2 = reject;
    });

    p1 = new Promise(function(resolve1, reject1) {
        action.setCallback(this, function (response){
            // which resolve function to use?
            var resolve = firstTime ? resolve1 : resolve2;
            var reject = firstTime ? reject1 : reject2;
            firstTime = false;

            if (response.getState() === 'SUCCESS') {
                resolve(response.getReturnValue());
            } else if(response.getState() === 'ERROR'){
                reject(response.getError());
            }
        });
        $A.enqueueAction(action);
    });

    return [p1,p2];
}

You’d pass an action into this function and get an array with two promises, [p1,p2]. The first (and possibly only) time a value returns, it will resolve p1. If a second time happens, it will resolve p2. So this way you can specify different behaviours to follow through with if p1 is returned vs p2.

A somewhat messy thing is that we export the resolve and reject functions of p2 so that they can be addressed in the scope of p1’s function. But this gives us the ability to choose which promise resolves when the callback executes.

Any better ideas? Comments/suggestions?

Attribution
Source : Link , Question Author : jmdohn , Answer Author : Charles T

Leave a Comment