ADF Performance Tuning: Avoid a Long Browser Load Time
It is not always easy to troubleshoot ADF performance problems – it is often complicated. Many parts needs to be measured, analyzed and considered. While looking for performance problems at the usual suspects (ADF application, database, network), the real problem can also be found in the often overlooked browser load time. The browser load time is just an important part of the HTTP request and response handling as is the time spent in the applicationserver, database and network. The browser load time can take a few seconds extra time on top of the server and network process time before the end-user receives the HTTP response and can continue with his work. Especially if the browser needs to build a very very ‘rich’ ADF page – the browser needs to build and process the very large DOM-tree. The end-user needs to wait then for seconds, even in modern browsers as Google Chrome, Firefox and Microsoft Edge. Often this is caused by a ‘bad’ page design where too much ADF components are rendered and displayed at the same time; too many table columns and rows, but also too many other components can cause a slow browser load time. This blog shows an example, analyses the browser load time in the ADF Performance Monitor, and suggest simple page design considerations to prevent a large browser load time.
End-user experience of a HTTP request
The end-user experience of a HTTP request is the sum of the time spent in the following layers:
- Execution time in the database and/or execution time in webservices
- Process time in the application server
- Network time. This is the time that it takes to send a HTTP request from a browser (http request network time) to the application server and from the application server back to the browser (http response network time). See also this blog.
- Browser load time on the client side. This is the time that a browser needs to build up the DOM tree and load the page.
Slow Browser Load Time Reproduced
I have seen many business critical ADF applications that display and render far to many columns – I have seen many tables with more than 50 columns(!). But also 25 columns is a lot. The problem becomes worse and worse if there are many rows as well (more than 100) rendered at the browser.
Lets reproduce it first, with an ADF app on the HR schema (first 75 columns and 50 rows are rendered at the same time):
The click-actions of opening the Locations page, scrolling down, selecting a row, feels absolutely not like a nice experience – we have to wait a few seconds (including browser load time, as the end users experiences it). This is serious annoying for end-users if this is a page used intensively.
HTTP Request Details in the ADF Performance Monitor
Lets go now to the ADF Performance Monitor to analyze the browser performance. An exiting new feature of the ADF Performance Monitor is that it can measure time spent each layer for each HTTP request – but now also the network time and browser load time separately. We can now analyze the Locations page:
At the HTTP Requests detail page we can see the time spent each layer for each HTTP request – visible in a status-meter. The length of the status-meter corresponds to the total response time as the end-user experiences it including network time and browser load time. This is useful for troubleshooting performance issues – in one glance you can see in which layer the time is being spent:
- database-time (yellow)
- webservice-time (pink)
- applicationserver-time (blue)
- network-time (purple)
- browser load time (grey)
We can get the actual times of the browser load time by adding the column browser load time:. As we could see already in the statusmeter but now also in a separate column, the browser load time of our page is around 1 to 1,5 seconds – this is very long for a modern browser.
A page should spent not more than half a second or less in the browser to load, usually not more than 0,25 second (250 Milliseconds).
We can check the ADF Faces Component ID that was initiating the request, the ADF Faces Component Type and the ADF Faces Component Display Name if present in the ADF application. So our Locations page can be loaded by:
- Opening the Locations tab (comp id: pt:dyntdc:dynTabsPane:1:tabIndex, comp type: RichCommandNavigationItem)
- User scrolls down the locations page (comp id: pt:dyntdc:r1:1:t1, comp type: RichTable)
Even Slower Browser Load Time
Lets look what happens to the browser load time if we set the fetchsize of the af:table to more than 50, lets say 250. For this we set the rangesize property of the Locations iterator in the LocationsPageDef (this where the fetchsize of the table points to by default):
Now we see that the browser load time has increased, and is now around three seconds (!):
Even More Slower Browser Load Time
If I change the rangesize to 1000 for testing purposes – which is ridiculous of course (1000 rows are being send to the browser) – we see that the browser load time increases and becomes more than 30 seconds in Google Chrome:
In my test Microsoft Edge couldn’t even load the page in this case.
In the overview dashboard, at the hour overview we can see also the performance by layer at the right bottom – including browser load time:
Conclusion: Design your ADF pages not too ‘rich’
The conclusion is that we shouldn’t make our ADF pages too ‘rich’ – we should limit the number of ADF Faces components to some extent. Especially the content of ADF Faces container components. Rendering too many table columns – in combination with sending too many rows to the browser – causes a long browser load time. I had the same problem with an af:listView after rendering more than 50 rows already. The same with af:tree and af:treeTable components with hundreds of expanded nodes; this needs also process time in the browser. But also other container components like af:iterator – when too many child components are rendered – the browser needs seconds to do the hard work.
Some general tips:
- Don’t set the fetchsize property of an af:table, af:treetable or af:listView to more then the number of rows displayed on the browser (set it to less than 40)
- Don’t use more than 20 columns on a table if possible – display only the most important columns. Do not display/render data that is not immediately needed. Move extra (detail) columns to detail pages or detail popups
- Expand af:tree and af:treeTable components to at maximum one or two levels deep if you have hundreds of nodes or more
- Readonly tables load faster than editable tables. Use EditingMode=”clickToEdit” instead of always editable
- Another way how you can ‘lazy’ load extra columns in a very simple way – and improve the browser load time – is to render columns on demand, for example by showing a show/hide checkbox:
- Use rendered instead of visible to display components conditionally
- Several properties like af:popup have the property contentDelivery. set this to lazy or lazyUncached
- Make IDs of the following ADF faces container components as small as possible (max 2 characters):
Conclusion: Do not display too much ADF Faces components on a page and keep your page design simple.
This blog was posted by Frank Houweling