Are the details of the Boxcaring is removed from LWC components? answer from January 2020 still largely correct - has anything in this area changed?
I wrote an app for this, and I found that all requests are queued up and loaded at once for initial wire methods and connectedCallback calls. Even as few as 2 calls to the server will go together, rather than in parallel. I'm not sure if it's always been this way, or when it changed, but it's here now.
After the connectedCallback for all components has completed, the boxcar effect works as it always has; if there are fewer than 5 requests in-flight, they will go independently, but the sixth slot will be used for boxcar requests.
Here's the original app I used to identify this behavior:
Apex
// Waits one second
public with sharing class q361552 {
@AuraEnabled(cacheable=false)
public static void wait(Integer i){
DateTime start = DateTime.now();
while(DateTime.now().getTime() - start.getTime()<1000);
}
}
LWC HTML
<template>
{message}
</template>
LWC JS
import { LightningElement } from 'lwc';
import wait from '@salesforce/apex/q361552.wait';
export default class Q361552 extends LightningElement {
message = 'Start loading...';
connectedCallback() {
Promise.all(
[...new Array(2).keys()].map(i => wait({i}))
).then(() => this.message = 'Done loading!')
}
}
AURA APP
<aura:application>
<c:q361552 />
<c:q361552 />
</aura:application>
Now, we check the network tab...
Request message
{
"actions": [
{
"id": "1;a",
"descriptor": "aura://ApexActionController/ACTION$execute",
"callingDescriptor": "UNKNOWN",
"params": {
"classname": "q361552",
"method": "wait",
"params": { "i": 0 },
"cacheable": false,
"isContinuation": false
}
},
{
"id": "2;a",
"descriptor": "aura://ApexActionController/ACTION$execute",
"callingDescriptor": "UNKNOWN",
"params": {
"classname": "q361552",
"method": "wait",
"params": { "i": 1 },
"cacheable": false,
"isContinuation": false
}
},
{
"id": "3;a",
"descriptor": "aura://ApexActionController/ACTION$execute",
"callingDescriptor": "UNKNOWN",
"params": {
"classname": "q361552",
"method": "wait",
"params": { "i": 0 },
"cacheable": false,
"isContinuation": false
}
},
{
"id": "4;a",
"descriptor": "aura://ApexActionController/ACTION$execute",
"callingDescriptor": "UNKNOWN",
"params": {
"classname": "q361552",
"method": "wait",
"params": { "i": 1 },
"cacheable": false,
"isContinuation": false
}
}
]
}
And the timing tab confirms that the request took over 4 seconds.
So, adding a small delay, even 100ms, to initial requests will allow for the boxcar effect to work normally (you can use setTimeout for this). You might be able to get even better overall performance if you randomly stagger the requests with setTimeout.
If there are any strategies beyond serious refactoring or using setTimeout (see the answer to How to turn boxcarring OFF for LWC imperative apex method calls?) to alleviate the problem?
There is no real "workaround", just general advice. First, avoid calling imperative Apex in connectedCallback; use setTimeout if you need to. Second, prefer imperative Apex to wire methods. Third, use cacheable methods as much as possible for fewer server calls. Fourth, if wire methods are the best way to do something, make sure you optimize your Apex to use as little resources as possible; while governor limits are per-method-call, these methods do not run in parallel, so will affect overall load time.