7

Lightning Component Action Service uses a "boxcar" pattern to bundle server-side action requests into a single call, executes them all on the server, provides a bundled response and then the framework deconstructs the response on the client. Awesome! This reduces the number of requests and is ideal in most cases.

Occasionally, there are use cases where a small request and a large request are both enqueued and bundled together and the small request has to "wait" for the large request to finish. Or a bunch of larger actions might want to be "lazy loaded" in a feed (images or document bodies or something). I'd like to see file1 load, then file2 load, then file3 come in in succession. Instead, I see (long wait 10s), then file1 2 and 3 all come in at once.

As a developer, I need to be able to control this behavior and separate the server actions to provide a responsive user experience.

Peter Chittum discusses "Exclusive Actions" here http://pchittum.com/2015/04/28/Lightning-Component-Exclusive-Actions/

But the setExclusive method seems to now be deprecated https://github.com/forcedotcom/aura/blob/65ebdaca6501972ea621f193d1284ec14b848e03/aura-impl/src/main/resources/aura/controller/Action.js#L1078

Additionally, setting setBackground to true when enqueueing the action doesn't seem to help either (specifically in the lazy load use case). It still holds to the wait-10-seconds, then all 3 files are displayed pattern.

I am not able to find any write-ups or documentation on the deprecation or alternatives for Exclusive Actions. Are there alternatives to Exclusive actions and/or a method for a developer to explicitly separate server-side actions?

Thanks.

  • You're right, that did get deprecated. I should update that blog. To make to discrete calls, I have created two actions, enqueuing the one, and then enqueuing the second on the callback of the first. But my example was on retrieving data (populate parent record and display, before populating a child list, for instance). Let me see if I can write up a little sample code for an answer. – pchittum Dec 8 '16 at 9:18
3

The only way I know of ensuring that two actions do not share the same server round trip is to trigger the second (we'll call it the child) from the successful callback of the first (yep...the parent).

To tell this story, I'm going to use the classic let's-save-a-account-and-a-contact story that we all know and love. And for some reason...unbeknownst to us...we have to do it in two calls. Although we could extrapolate this into one of your use cases: you have a large call, like a file, and a smaller one, a record. Maybe you want to get the smaller one done first, get on with things, so the larger request can be done and if the user happens to still be there when the request is done...great...otherwise, they've moved on.

So I've got two actions:

let saveAccount = component.get('c.createAccount');
let saveContact = component.get('c.createContact');

And then I do all of the setup for the first one:

saveAccount.setParam('acct', component.get('v.account'));

saveAccount.setCallback(this, function(response){

    ...process account return value, we get an Id, set it into the contact, etc. then...

    saveContact.setParam('cont', component.get('v.contact'));

    saveContact.setCallback(this, function(response){

        let savedContact = response.getReturnValue();
        component.set('v.contact', savedContact);

    });

    $A.enqueueAction(saveContact);

}); 

$A.enqueueAction(saveAccount);

Doing a lot of this could definitely send you quickly on the path to callback hell, Lightning style. But the first time I did this it was for retrieving first a parent record, then a big list of a bunch of other records. That second request was larger busier, etc. But still the user got the primary record loaded up pretty quickly.

One last thing...I like doing this with a named callback. This flattens out the callback hellishness a bit and gives errors a named thing to report to when they happen there. However this requires a closure to keep component and possibly event in scope .

Function generator (helper is a good place for this):

myfuncgenerator : function (component, event) {

  return function(response){
    let comp = component;
    let evt = event;

    ...do lot's of cool things...

  };

}

Then in your other code something like

let callbackFunction = helper.myfuncgenerator(component, event);

...

myAction.setCallback(this, callbackFunction); 

Looks much nicer, IMO.

I'm not sure what happened to "cabooses". That always seemed like a good idea, as did setExclusive. The idea that the framework does this for me seems better than this way of having to roll your own. But for the time being...roll away.

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.