Primeng: Performance

Created on 7 Aug 2016  路  28Comments  路  Source: primefaces/primeng

Hi,

When I quickly moving the mouse over some components (especially over datatable), the cpu usage grows up highly (it also occurs in firefox and chrome) (perhaps best seen in here: http://www.primefaces.org/primeng/#/datatableselection ). It also happens when I using components in datatable, like input or autocomplete and clicking into them. It makes my app laggy because I use datatable in many places. I think it's angular problem, but it's occours everyone?

Most helpful comment

Hi guys,

Is there any plan to address this issue? Not sure why it's not upvoted more since it makes the DataTable pretty much unusable in my experience...
Thanks!

All 28 comments

That's not angular really, this is a byproduct of the datatable itself. There are two methods defined.

mouseenter and mouseleave, and these are being called when your mouse cursor enters any of the rows or columns. This isn't new, this used to bog down JTable in Swing.

The problem you appear to have is mouseenter in the datatable and then the mouseenter or hover functions being called for every component in the row.

I don't think the NGPrime team could actually optimise for that.

Thanks, I think it's a big problem. My temporary workaround is to catch mousemove, mouseout, mouseover, mouseenter, mouseleave, scroll events, and if the event target or related target not matching that what I need then I call event preventDefault and stopPropagation methods.

Would love to see a fix for that. Indeed a very big problem. For now I'll try to implement @izll 's workaround. @izll , could you spare an example of how and where you catch those events?

Yes, of course, just include this in your app.html after jquery:

document.addEventListener("mousemove", function (event) {
    var target = $(event.target);
    if (target.is("path")) {
        return;
    }
    event.preventDefault();
    event.stopPropagation();
    event.cancelBubble = true;
}, true);

document.addEventListener("mouseout", function (event) {
    var target = $(event.target);
    if (target.is("rect")) {
        return;
    }
    event.preventDefault();
    event.stopPropagation();
    event.cancelBubble = true;
}, true);

document.addEventListener("scroll", function (event) {
    event.preventDefault();
    event.stopPropagation();
    event.cancelBubble = true;
}, true);


document.addEventListener("mouseover", function (event) {
    var target = $(event.target);
    if (target.is("a") || target.is("img") || target.is("rect")) {
        return;
    }
    event.preventDefault();
    event.stopPropagation();
}, true);

document.addEventListener("mouseenter", function (event) {
    var target = $(event.target);
    if (target.hasClass('ui-autocomplete-list-item') || target.hasClass('ui-dropdown-item')) {
        return;
    }
    var relatedTarget = $(event.relatedTarget);
    if (relatedTarget.hasClass('ui-autocomplete-list-item') || relatedTarget.hasClass('ui-dropdown-item')) {
        return;
    }
    event.preventDefault();
    event.stopPropagation();
}, true);

document.addEventListener("mouseleave", function (event) {
    var target = $(event.target);
    if (target.is("a") || target.is("img") || target.is("rect")) {
        return;
    }
    if (target.hasClass('ui-autocomplete-list-item') || target.hasClass('ui-dropdown-item')) {
        return;
    }
    var relatedTarget = $(event.relatedTarget);
    if (relatedTarget.hasClass('ui-autocomplete-list-item') || relatedTarget.hasClass('ui-dropdown-item')) {
        return;
    }
    event.preventDefault();
    event.stopPropagation();
}, true);

Thanks @izll ! Of course this workaround is only good as a temporary workaround indeed.
You could also use HostListener to catch these events "the angular way" and use it only on the relevant component.

Digging around the code I noticed the datatable handles change detection by it's own.. calling this complex change detection logic for every mouse move seems insane to me.
Changing this method to perform reference comparison is my temporary fix - I still have great lag so I have to dig more, but it's much better than before.

Hi guys,

Is there any plan to address this issue? Not sure why it's not upvoted more since it makes the DataTable pretty much unusable in my experience...
Thanks!

Switched to another table for now. This one's a showstopper..

@jonyadamit I have same issue with datatable, which one you choose to solve this?

@sentyaev I don't think it would be right of me to endorse specific alternatives in here, I was mainly conveying the seriousness of this issue.
I will nevertheless give you that answer in private 馃槈

I think, the problem is more general in primeng. It's about setting the ui-state-* classes for stylings. Every mouse enter and leave event kicks in a change detection phase. This can cause big cpu usage on a comppex page.
I think this is a bad legacy from the jquery based css of primefaces, where supporting older browsers was a goal. But since angular is targeted for modern browsers, I don't see any reason to continue this bad pattern. CSS can be used for this definitely.

This issue needs to be targeted, otherwise there will be always performance problems in the framework.

How are you going to enable and disable the css for the row you need? CSS might speed it up, but you still need to decide which column or row the mouse has entered.

I have never noticed an issue with Chrome. I have with an older version of Edge, but since the latest version of 1607, not again. Firefox on the other hand is treacle.

@garethlewis using :hover?

Not going to help, actually that is worse. hover causes a reflow event in the brower, where the browser as to work out what has changed. That's even worse than you setting the css yourself.

What can be worse than triggering Angular Change Detection on every mouse enter / leave. This happens everywhere: inputs, buttons, all components.
And I don't believe that changing a class don't do a reflow as well.

True, but just replacing everything with hover, doesn't solve anything. Doing anything with CSS, like changing an attribute causes a reflow.

The solution we followed for this performance issue was to more-or-less implement a custom DataTable component ourselves, which uses a separate Angular 2 component for each row.
The problem with the PrimeNG DataTable is that for many columns and rows each template expression, generated in the DataTable template (using the ngFor loops), will need to be checked in each change detection cycle. The next problem in solving this was, that the PrimeNG DataTable itself is unable to support Angular 2 OnPush change detection, because it is just one component.
Therefore, we used a custom "row" component with OnPush.
The next problem was that in Angular 2 each component's selector element, which is used to include that component in a parent's HTML/template, will always be rendered in the final HTML output and making a custom "row" element being a element is not possible in Angular 2. To solve this we used a custom

element with a "display: table-row;" style to make it layout just like a table row element.

@httpdigest Would you be willing to open source your solution as an alternate datatable implementation?

I just sketched a possible solution for the performance problem, which we just implemented a simple scaffold for. This is in no way a complete solution that can readily replace the existing PrimeNG DataTable component in its functionality.
My hopes were that PrimeTek would pick up on the solution strategy and realize that in their own DataTable. Or that they just comment this ticket for once. :)

I'd be happy to take a look and possibly adapt it, you could post a pull-request to my fork.

Yep, this is a very bad decision - i have 100% CPU usage on my laptop (intel core i7, ssd and 16gb ram)!
CSS pseudo classes :hover and :active can help with this issue.

UPD.: also i see in timeline (chrome debug tools) when set in datatable 100 rows - change detector going crazy. Is this article helps with refactoring https://www.lucidchart.com/techblog/2016/05/04/angular-2-best-practices-change-detector-performance/ ?

just spent the past hour implementing this data table only to find it performs really badly. The rest of the UI becomes sticky and slow, and that's only binding to 50 rows of data...

I wonder if just adding some sort of throttling to the checks that trigger change detection would help? e.g. once every 50ms or something. It's not a true solution, but at least it would greatly reduce the number of change detection passes.

@cagataycivici I am sorry to ping you like that but this issue is more than 4 months old with no answer from you. I have a simple question, should we move on with another grid or should we wait for possible solution?
There is really no use of having the most advanced datatable out there if nobody can use it for something more than a school project.

@moxival I saw in a blog that v2.0 will be more performed (pseudo classes instead of setting css in components - it will be faster ~20%)
Also you can fork datatable, and play with changeDetection: ChangeDetectionStrategy.OnPush

@brud Thanx for the tip, I do know that i can "play" with CDS and i have played with it. Unfortunately most of the primeng components are incompatible with OnPush strategy and you end up with open dropdowns and calendars that will not close until you hover them, fields that will not populate if you don't click/hover them etc.
What I wanted was an answer from some of the guys behind PrimeNG actually. Also i would like to see IF the problem with the datatable is actually the changing CSS classes and it has nothing to do with the custom change detection implemented in the data table.

2.0 fixes this, documented at the official announcement as well;

http://blog.primefaces.org/?p=4341

We now use css pseudo so mouse movements do not trigger change detection.

2.0 fixes working for dropdown inside datatable.
But the issue still exists for autocomplete.
Am having dropdown and autocomplete components in datatable rows.
when the row count reaches 25+ rows with autocomplete component then the click event takes more time to focus cursor on that element.
it is fast if i remove that autocomplete component and have 25+ rows.

running < 2.0 here and tried dropping the aforementioned listener mods after import $ from 'jquery' and it's still not working. anyone else see this?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

philly-vanilly picture philly-vanilly  路  3Comments

miresk picture miresk  路  3Comments

jisqaqov picture jisqaqov  路  3Comments

just-paja picture just-paja  路  3Comments

KannanMuruganmony picture KannanMuruganmony  路  3Comments