Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Chrome use more CPU when a large Knockout element is hidden?

I have a single-page web app that uses Knockout.js 2.2.1 to display information streaming from a server (using socket.io, although I don't think that matters). This app also contains a large data table, which is created from a JSON object using Knockout's foreach bindings. (The table is big, but not enormous: 20 columns and 200 rows or so.)

Since the table is large, it can be opened/closed by the user by clicking buttons. The data <table> is placed inside a <div> element that I can hide/show using jQuery's .hide() and .show() methods (which essentially work by setting and clearing CSS display: none on the <div>).

All of this functionality works. However, I notice that after 'closing' (hiding) the big data table, Chrome's CPU usage jumps - all the way to 100% if the Knockout-generated table is big enough. What's more interesting is that this only happens after the user has clicked somewhere inside the <div> element that contains the table when it is shown. When the table is hidden (and CPU usage is high), clicking somewhere else on the page will return CPU usage back to normal. The process will repeat at will.

Another possibly useful note: if I stop the streaming data from the server this problem doesn't happen (or, it's not noticeable in the CPU usage). There is a single Knockout view model on this page, which manages both the streaming data from the server and the creation of this data table from a JSON object. The two sets of data are otherwise completely separate - none of the changing data is displayed in the table, and the table contains no event bindings back to the view model. It's as if the streaming data update of the Knockout model is causing work on the data table even though none of the streaming data is bound to the table. And it does this only when the table is not displayed!

Quick summary:

  • Web app uses Knockout to render a large data table when the page is loaded.
  • This table is hidden with .hide() at startup in $(document).ready, but is displayed using .show(), after clicking a button, and can be hidden again
  • If the mouse is clicked inside the data table, CPU usage in Chrome will jump to 100% after the table is hidden again.
  • Clicking anything else on the page will bring the CPU usage back to normal.

Other relevant information:

  • The Chrome JavaScript profiler shows the high CPU usage, but it's categorized simply as (program) time.
  • Neither IE10 nor Firefox 20 on Windows show this problem.

Any ideas what's going on here, or suggestions for additional troubleshooting?

jsFiddle:

Example here: http://jsfiddle.net/CTYMv/6/

Look at CPU usage after loading the fiddle, it should be low. Click "Show Table", then click somewhere inside the div that pops up (gray background). Then click "Hide Table" - CPU usage will increase significantly. Then click anywhere else (white background), and CPU will return to normal.

like image 501
potatoe Avatar asked May 07 '13 05:05

potatoe


People also ask

Why is Google Chrome so CPU intensive?

As TechStacker explains, there are many possible explanations for high CPU usage in Chrome. These typically relate to your browsing behavior, including having too many tabs open at once, too many apps or browser extensions running and streaming high-quality video.

Why do some websites use so much CPU?

The most common causes for high CPU usage in your browser are: Too many apps running at the same time. Like browser extensions, which are small software packages that add functionality to your browser. Too many browser tabs open at the same time.


1 Answers

I think we can now argue this is a bug in webkit engine. This bug only appears when using css property display:none;. Is it due to how GPU using webkit render hidden elements? Well, i still don't know...

SEE DEMO

This is the simplest workaround i can think of, this should not interfered with any of your other code: {e.g knockout observable}

CSS: {added pointer-events as suggested by Brandon}

.hidden{opacity:0;pointer-events:none} //don't use display:none here 

JS:

//don't use hide/show jq methods as internally it set display none (fadeOut() methods too) $('#btn_show').click(function(){     $('#bigdatadiv').removeClass('hidden'); }); $('#btn_hide').on('click',function(){        $('#bigdatadiv').addClass('hidden') }); 

I'm aware this is just a workaround and that still not answering your question: why this is happening?

like image 175
A. Wolff Avatar answered Sep 27 '22 22:09

A. Wolff