Feedback from Salesforce core engineering team
Added by @salesforce-sas and updated by @PhilW:
There were major design changes rolled out in Winter '20 affecting the way server calls are made. Everything in LWC are separate parallel calls to the server at the Lightning Data Service (LDS) layer. However, the boxcarring effect kicks in at the Aura Data Service (ADS) layer (currently the intermediary between LDS and the server) when all available parallel XMLHttpRequests (XHRs) from the browser to the server are busy.
Currently all browsers support 6 parallel XHRs as standard. When ADS has started 5 concurrent XHRs, the 6th (last one) boxcars and sends all the remaining server calls queued by the LDS. This is the reason that, although we see only 6 XHRs in browser network tab, we will see individual apex logs per request in the Salesforce Developer Console.
This is not documented because the Salesforce dev team is continuously trying to improve server calls (LDS) and this design/implementation is not the final one. It is doubtful that these design changes will ever be documented.
We haven't seen any changes to boxcarring, at least in the last 6-7 months from when we started looking at this. There are specific details on how LEX and LWC are working that haven't been explained anywhere that I've found which may be affecting what you're seeing.
If you load a page with a large number of components in it that do a lot of different wire or imperative calls you will see that the way the LEX/LWC infrastructure works is:
- Up to 5** wire or imperative calls invoked "at the same time" are processed in parallel (@salesforce-sas reports he has seen 6 or more though this isn't something I have seen for "at the same time" calls. He also states that this specific aspect has changed since his testing in July '19. I can't comment as that is around when we started looking into this behaviour)
- Further calls starting "at or around the same time" get boxcarred
Here's an example. We have a grid (component). The grid is populated with visual representations of SObjects (component). Each cell (component) in the grid performs its own (here imperative) call to the server to fetch its data then uses that to create the SObject representations. Once completely rendered it looks like this:
However, when the grid is first being rendered in the LEX Object Record Page, we see:
You can see that only 5 cells have executed their calls and been rendered; all the other cells are still waiting. Once the waiting has finished, the next thing the user sees is basically the completed picture (first figure, above).
If you look at the network traffic you see the following:
You can see that the first 5 wire/imperative calls are allowed to run in parallel. Once one of these has finished (so there is an available "thread" from the LEX perspective) you then see that almost all the other requests get collected together and run as a single invocation to the server - this is the boxcarring in action.
** It is worth noting that the various browser implementations actually limit the number of "parallel" AJAX calls to the same host. For Chrome it is 6. This may mean you see different behaviour on different browsers. Take a look here for some further details.
To conclude - boxcarring is still there, but if you keep your number of "start at or around the same time" calls to 5 or less no boxcarring will happen. We use this to good effect in some of our other components where we specifically orchestrate our (imperative) calls to the server to do 5 or less at any one time. Other requests get postponed and are started when an existing request completes.
PS: One thing that did change recently - boxcarred requests now correctly each get their own limits. This wasn't the case previously due to a bug in the platform.