Tuesday, May 7, 2013

JSF: choice between legacy components and fashionable performance killers

This blog post was originated due to performance issues in one big web application. Everybody optimizes Java code, but it seems nobody try to optimize the JavaScript code. Strange, because on the client-side there is much room for improvements. I would state, even more than on the server-side. We will analyse the perfomance of editable JSF standard components, sometimes called "legacy", and modern PrimeFaces components with rich JavaScript widgets. This is a neutral analyse, without to blame any library or any person. Only facts.

Well. What do we want to test? The goal is to measure the client-side perfomance (without backend logic) of JS script block executions for PrimeFaces p:inputText / p:selectOneMenu. We want to test an editable p:dataTable with inputs / selects components in table cells. The table has 25 rows and 16 columns, that means 25 * 16 = 400 cells. Every cell contains either an input or a select component. There are 6 test cases. Standard h:inputText and h:selectOneMenu don't have JS script blocks, so it is interesting to see what for impact JS widgets have.


The entire test project is available on GitHub. Simple clone or download it and run with built-in Maven Jetty plugin. The page load speed is measured with the new Navigation Timing JavaScript API for accurately measuring performance on the web. The API provides a simple way to get accurate and detailed timing statistics. It's more precise than using JS Date object. The Navigation Timing JavaScript API is available in Internet Explorer 9 and higher, last versions of Google Chrome and Firefox. The code to measure the time after the current response has been arrived until the window onload event is fired is shown on the GitHub.

JavaScript is single-threaded, so let's see how sequential script block executions can slow down displaying a web page. If we only test h:inputText and p:inputText, the difference is marginal. The page load time is almost the same. Running on Windows 7 and Firefox 20.0.1 I could only see that the table with p:inputText needs ca. 200-300 ms more than the table with h:inputText. This is a good result which means the JS script execution for one p:inputText takes less than 1 ms. Really good. Congrats to PrimeFaces. A mix test with inputs and selects shown that the page with PrimeFaces components takes approximately 1.5 sek. more than the page with standard components. Adding more PrimeFaces select components slows the page rendering time down. Extreme case is to have only p:selectOneMenu components. This is a perfomance killer and the reason why our web application was too slow. Internet Explorer shows the well-known error message "A script on this page is causing Internet Explorer to run slowly". Take a look at page load time self.

Running on Windows 7 and Firefox 20.0.1

h:selectOneMenu

 

p:selectOneMenu


If we assume that component renderers take approximately the same time to render HTML output, we can calculate the time for JS script block execution of a single p:selectOneMenu. This time is 11,3 ms. That's too much. The reason may be many inefficient jQuery selectors in widget's constructor. I don't know and it doesn't matter here. On my notebook with Ubuntu, I got a huge time difference ca. 10 sek. The browser with 400 p:selectOneMenu tags almost "freezes".

Running on Kubuntu 12.04 and Firefox 20.0

h:selectOneMenu


p:selectOneMenu


Conclusion

Some people say "JSF is slow, JSF is not a right technology". Wrong. JSF is fast enough. It depends on how to use this framework. Editing of everything at once is nice, but obviously it is not recommended to use a large editable DataTable with rich JSF components. What would be an alternative for editable DataTable? There are many ways, depending on individual preferences. I will try to propose some ones.
  1. Use standard JSF select components in large editable tables. But what is with theming? No problem. All modern browser, also IE8 and higher allow to style native HTML select elements. You can adjust colors for borders, background and let selects look more or less stylish according to applied theme. Presupposed is of course, you don't need advanced features such as custom content within select components (filter functionality or whatever).
  2. Cell editing feature in PrimeFaces renders native select elements and it is fast.
  3. Row editing feature in PrimeFaces renders native select elements and it seems to be also fast.
  4. Master-Detail approach in one view. You select a row and see details to edit. Details can be shown outside of the table - on the right side or at the top, depending on table's width / height.
  5. Master-Detail approach with separate views. You select a row and switch the views. Instead of table, you see details like in the MasterDetail component of PrimeFaces Extensions. From details you can go on to another levels to create / edit more details and then, at the end, jump to the overview table again.
I hope, you enjoyed this post :-). Comments and suggestions are welcome.

17 comments:

  1. should do performance testing for all components

    ReplyDelete
  2. +1,000,000,000...

    Oleg, as someone that has had success using and developing JSF web application with 'rich content' (primarily because of PrimeFaces), and now more focused on performance of the JSF web application... I really like/love this blog post, and agree with (practically) everything you said.

    I 'only' use h:selectOneMenu in my JSF web app, and myself and endusers love it, especially, since they/we came from a MS-DOS dBase IV window/app, where use of keyboard was necessary and required, and mouse was not used at all in the legacy app. The endusers (and myself) have migrated very very well to the JSF web application within the last year (since the JSF/PrimeFaces web application started to be used July 2012...after using MS-DOS dBase IV app since 1994/1995).

    One of the endusers asked for a 'catch-all' page that allows input of all possible data fields for a (purchase) 'order'. So, I developed that, and the page has to have 100s of inputs, including h:selectOneMenu, p:inputText, at least 6 p:autoComplete, and Google Places Autocomplete javascript API added to some of the p:inputText...for geocoding, etc...

    That page takes a long time to load and/or render, especially on mobile devices. I have not timed it recently, but it takes at least 2 to 5 seconds to render, and there is sooooo much javascript on the page which is associating Google Places Autocomplete to some p:inputText, and javascript that disables many many components onLoad or jquery onload event.

    One of the endusers of the app, requests for a lot of features to be added to the Java/JSF/PrimeFaces web app, and for enhancements, if he doesn't like something about the web pages. Anyway, he recently, informed me that that page does take a long time to render/load (even though I knew that already), so I told him that I will change that page, where the page, initially renders with very little of the content, and add a More... commandButton, which will render the rest of the content. The entire page is not even used much, right now or anymore, because I have added other features like 'templates' and 'copy', where you can save orders as templates and copy existing orders, etc..., and now i have the public website, somewhat integrated to the (private) JSF web application, so customer requests are automatically imported into the database...from the public website.

    Back to the topic...I also agree that, i don't know why so many PrimeFaces users feel as though they need to have editable datatable with many rows. okay, I do have a requirement and use case of editable datatable, but the page has tabView with 3 tabs, one datatable per tab, and at least 60 to (almost) 300 rows per datatable. There is Save button at top of page and nothing fancy about the page at all; just p:dataTable, p:selectOneMenu, 1 or 2 p:dataTable at top of page displaying some 'detail' data about certain order, and the few command buttons. Definitely no filter, no 'editable' datatable, no selectOneMenu. it is a page to enter miles traveled within cities, counties, towns...for a report that needs to be submitted to local authorities. :)

    I also have dataTable with multiple row selection, buttons at the top of page, some buttons require one row to be selected, some buttons 'allow' multiple rows to be selected. select one row, click different buttons, and other content/pages will be rendered via ajax="false" or ajax="true". I like that approach, and the endusers love it as well...for the most-frequently-used datatable page and view page and edit page...in the app. I learned this approach from BalusC blogspot. traditional JSF...which works!

    hmmm, can't think of anything else to say right now...gotta get back to work, trying to add some new content/functionality to the JSF web app. I love Java/JSF/PrimeFaces and last but not least...TomEE!!!!!!!!!

    ReplyDelete
  3. shaking my head, for some reason, i had freudian slips in my previous post above, anywhere, where you see that i am 'using' p:selectOneMenu, i meant to say that i am using p:inputText. i replaced one p:selectOneMenu with p:inputText, but forgot another p:selectOneMenu (where i was talking about the page with tabview, datatables, and correction, with columns containing p:inputText).

    ReplyDelete
  4. @Howard: Thanks. Agree, good design = good performance. I recently bought two books for understanding better user-friendly UI designs :-). But sometimes you don't have much choice when customer or your employer say "we only want to have and like the approach to edit everything at once, in one view, etc." :-).

    ReplyDelete
  5. Thanks for sharing this info. Nice.

    ReplyDelete
  6. While the test and its results are valid and point to possible optimisations that need to be made in PrimeFaces I see a much deeper problem with the design if this is a reflection of the original web application: the fact that so many p:selectOneMenu components are being rendered does not strike me as being close to an optimal design choice. Why weren't inplace/cell or even row editing used instead?

    And why doesn't blogspot allow me to edit my own comments??

    ReplyDelete
  7. Andy, don't know, I was not the designer of this web app. In the fact already 50-80 p:selectOneMenu make a difference ca. 1 sek. This is too much. They are also response slow for me when you try to open the drop-down. Do you remember the client-side perf. problem with checkboxes in a data table? As I said, there is much potential for improvement. Someone should test perf. bottlenecks on the client-side and pay more attention to that.

    ReplyDelete
  8. Reasons why response times, both for the initial page load and opening the drop-down, would be due to
    - the large number of document.ready wireups that have to be made + the rendering
    - the size of the DOM being manipulated when a drop-down is opened and closed.

    Native dropdowns don't suffer from this hence the vastly superior performance.
    At some point the boundaries of the possible are going to be reached, having 400 p:selectOneMenu components on one page seems to do approach this.

    Row and Cell editing causes components to be wired up and rendered on demand which explains why they perform so much better but this can cause issues with memory leaks due to poor JS engines with extended use over a longer time.

    Oleg, is this taken from an actual web app with so many p:selectOneMenu components or is this being used as a pure test case?

    Yes I do remember the horrible performance of checkboxes :)

    ReplyDelete
  9. Andy, example with 25 rows and 15 columns with input / select components is taken from a real web app.

    In Row and Cell editing case, editable components are already in the rendered HTML along with output components. Read-only outputs are visible, editable inputs are shown on demand without any AJAX calls. That means, the markup can be even bigger, but it's faster because PF renders native HTML select elements without script block after every select (as in case with p:selectOneMenu). As I said, JS runs in a single thread and sequential scripts executions can take some time.

    ReplyDelete
  10. Since the commentators here seem to be experienced JSF users, I would just like to ask why you have chosen it over plain JSP. The main thing that has put me off using JSF in the past has been the awful HTML it generates. Using JSP just seems to give you more control over your application both performance wise and functionality wise.

    ReplyDelete
  11. I really like forgathering information , this post has got me even more info! than my expectations. web development company india

    ReplyDelete
  12. I have a dataTable with nearly 800 rows and 15 columns, 2 p:inputTexts and 1 p:selectOneMenu per rows......
    The table itself generated out about 6-7 sec, but no ajax event (rowToggle,rowSelect,unRowSelect) possible anymore. The whole datatable was sent to the server.

    According to this write i will check with h:selectOnMenu and h:inputText.

    ReplyDelete
  13. Hi,

    Thanks for the note. TechEmpower is doing benchmark test for all frameworks(http://www.techempower.com/benchmarks/#section=data-r5), in that JSF is missing. we have not yet received a Git hub pull request with a JSF implementation of the tests. If you have time to do the implementation yourself, we’d gladly receive a JSF pull request!

    They put this into a Github issue for the time being.

    https://github.com/TechEmpower/FrameworkBenchmarks/issues/307

    If plan to consider JSF, try it in following scenario

    A) Plain JSF Test

    1) Mojarra
    2) Myfaces

    B) JSF + Primefaces

    C) JSF + Icefaces

    D) JSF + Richfaces

    ReplyDelete
  14. Results are expected because p:selectOneMenu does not render a basic select tag, it has a bunch of divs, ul, lis, icons and more. Just because it looks like a select tag, it doesn't mean that it will perform the same. I would avoid using advanced rich components inside data iterations to save performance, it is not because selectors are inefficient, it is because rich ui elements are so complex with having advanced markup + js execution. h:selectOneMenu on the other hand has a simple select tag with no js execution.

    Still, if you don't use this fashionable performance killers inside a data component, they work just fine. This problem is not related to PrimeFaces, place a 3rd party fancy javascript library widget in a data iteration, it should more or less do the same.

    ReplyDelete
  15. Thanks Cagatay for your statement. Agree, it depends on JS complexity. p:inputText in data iteration components performs very well by the way, almost no difference to h:inputText. The more JS complexity, the more page load time. Small time differences are accumulate to a big one in data iteration components (with large amount of entries). This is the logical consequence, of course. So, no wonder.

    ReplyDelete
  16. I really appreciate your post which is definitely useful for me in the future.

    ReplyDelete