jQuery and DOM Manipulation Performance Issue in IE8 - javascript

I've developed a module at my work in JQuery, it is basically a table with the following functionality
Cell level Edit
Row level edit
Drop n drop rows to change position
Show/hide columns
Column resize
every thing works fine on latest browsers like, FF9.0, IE9 and Chrome, but in older browsers like IE8 and FF3.6 as the number of rows in the table increases the performance of the page reduces significantly.
I've tried many optimization from jQuery and DOM manipulation but still no effect on the performance. Any idea if I'm missing something or some tip to make the performance better i.e. to an acceptable level.
I haven't use any plugin, everything is my custom implementation. The javascript file is quite huge and I'm looking for some general good practices and tips.

There are two major ways to improve performance with large html pages - reduce the number of page reflows and reduce the number of handlers.
1. Reduce the number of page reflows
Every time you make a change to the DOM, it needs to redraw itself. This is a reflow. Keep these to a minimum by creating a string or DOM fragment with all your DOM manipulations, then inserting that into your page. This will trigger only one reflow. For example, if you're adding a table, create the whole table with text in it as should be, then insert that in a single operation.
JQuery allows you to create a DOM fragment like this:
var table = $('<table></table');
You can manipulate your fragment in the standard ways:
var line = $('<tr><td>Some Data</td></tr>');
line.css('color','red');
table.append(line);
Then when the fragment is complete, add it to the DOM in a single step:
$('body').append(table);
you will trigger only one reflow and the process will be orders of magnitude faster.
2. Reduce the number of handlers
If you have a lot of controls on each row, that's a lot of handlers. Instead create only one handler and attach it to the document root, then when it gets called inspect the target attribute to discover what to do. In JQuery you can use the new "on" handlers to do this, or else use the old "live" style handlers.
for example:
$('table td').on('click', function() {
//do work here
});
Only one handler will be created which will handle all of the td click events.
Do both of these and you should see dramatically improved performance.

The bad news is, there's not really much you can do as it mostly depends on the javascript engine used in the browser.
If it's an option for you try Google's Chromeframe for IE8, but on a public website that's most likely not a very nice solution. But it can be in a corporate environment when users can easily update software.
You could also try to render the table on-the-fly:
Ao you got your table and you got an array with information in javascript (or pullable via ajax), plus you got informations about where you are in the table (row) and how long the table is (maxrows).
Then create a table that's only as big as the viewport, maybe a little bit bigger. Everything above and below the viewport is handled by a big <div> or anything that is streched to the height of remaining rows or rows before the topmost in-viewport row.
That way only a very limited number of dom-nodes is present at any time. It could possibly improve performance.
When the user scrolls remove table cells that are no longer in viewport (and add their height to the respective whitespace block of that side) and add table cells that freshly came into viewport (removing the height from the whitespace on that side).

Related

Limitation of Angular and browsers with regards to data loaded

I would like to know what is the maximum data that angular framework can handle. Say, I am displaying a chart using angular and some charting framework like chartjs. I'd like to know up to how many data can the browser display properly, with slowness, or up to when it crashes.
Your question has no simple answer, but I will try to flatten it and give a simple answer, or at least simple things to consider...
Angular (at runtime), like many other frameworks is simply JavaScript,
So let us reduce the question to "Limitation of JavaScript and browsers with regards to data loaded",
JavaScript has no upper limit of memory or storage it can handle,
I've seen JavaScript applications that require more than 15GB of RAM,
and they performed well too.
So assume data size itself is not an issue (unless your application is poorly implemented, leaking memory or just not very efficient, of course).
The main challenge as I see it, is displaying and manipulating the information
without causing unnecessary delay or unresponsiveness.
Displaying the information - let's say you have a list (or a table) containing 1,000,000 possible gifts which you then want to display for the user to select.
Adding the list items to the document one by one is tempting, but will require the browser to repaint after each addition (causing a delay or full unresponsiveness until finished), another way is adding the elements to some DOM element (denoted by N) still being kept in memory, then adding all elements corresponding the list items to the element N (still, just an in memory operation), finally adding N to the document containing the entire list - the will be a much better solution for displaying the large amount of data.
Manipulating the information - displaying is indeed not enough. you would like to move, drag, sort and filter the data being displayed. And as mentioned before, it is a bad idea removing many elements directly from DOM. You should instead remove container from the document's DOM to memory, manipulate the data in it, and then add the container right back to the document. Angular does this kind of magic for you.
(Toggling the 'display:none\block' css attribute of many elements has a similar blocking effect as I recall).
A good practice is implementing an application/page showing only the amount of data that can be processed by a human at a single glance. The rest of it should be considered in the application data-layer, in memory, and should be loaded to display given the appropriate need or request.
To conclude, you can deal with huge amounts of data as long as you provide a mechanism that efficiently filter the displayed information.
I hope it helps...
for further reading:
Slow and fast ways of adding elements to DOM
A question emphasizes the lack of memory limit used by JS
CSS display attribute performance
A good discussion about the reasons for slow DOM
About using HTML5 correctly - old but still true
Once the DOM creation procedure is understood - it much easier to display data without affecting performance / user experience

Should I detach elements from the DOM while I apply many styles to them?

I'm concerned about performance and best practices.
So I'm building graphical UI and learned that I shouldn't call jQuery.append() a gazillion times when creating many small elements. So I got that covered by document.createDocumentFragment(). I'm adding elements to that, then once done, I insert the fragment to the DOM (with appendChild),
Then, in another pass I calculate where each element should be. Everything is absolutely positioned and will receive x and y values via CSS transform. Unfortunately, for these calculations I need the elements in the DOM since some of them contan random length text, and I need to measure widht/height. Otherwise I would perform step 3 on the document fragment directly, before it's even inserted into the DOM.
In the final pass I apply the calculated styles over everything with jQuery.css() (will likely replace with setAttribute instead of jQuery) as part of a loop (many calls to that, unfortunately - every element has different x/y). Should I detach the container that holds all my elements while I apply the styles, then reattach it to the DOM?
Due to lack of interest I decided to test it myself. Pulling an element of 700+ articles (15000 nodes), applying various CSS on the majority of them, then putting the element back into the page was actually slower by 50%. Let the browser do its job by only showing the results of changed attributes when Layout is needed.
I read the advice somewhere to remove the element from the DOM while working on it. While this could be true when appending elements to it, this does not hold true for style manipulations.

How to modify a large number of elements in DOM without sacrificing usability?

I have a list with quite a few elements (each of them is a nested div). Each element has a custom onclick handler.
JS updates the list several times per second, this may result in:
adding or removing some elements
changing text in some elements
changing styles in some elements
changing height of some elements
etc.
Most of the time the update makes small changes to the majority of the elements.
To minimize reflows I should remove the list from DOM, make the changes and append it back. The problem I have with this approach is that when user selects some text, the next update will reset the selection. (And the next update comes within a second) If user clicks a button his click may fail to register if there was an update between mose_down and mouse_up.
I understand when the selection resets on text that have been changed. It makes sense. But with such approach any selection in this list will reset.
Is there any better way to do this? How would you implement such list?
This list is fully generated by JS. If I'm removing it from DOM anyway, is there any benefit to modifying it instead of recreating it from scratch? Creating it anew each time would require less code.
This sounds like 2 way data binding, there are a couple of good custom solutions to data-binding answers on here: Handy stack link. Alternatively backbone.js and knockout.js have good techniques amongst quite a few other frameworks (angular ect).
Additionally, if you want to have a pop at it yourself (which I highly recommend to get a better understanding) you could use the proposed 'Object Observe' function. There's some handy documentation with some examples on how this works over at Mozilla. as well as The trusty HTML5 Rocks, which is a nice simple tutorial on using the new Object.Observe functionality, well worth a read.
Hope this helps!

ExtJS Grid storing Cell State automagically

I am porting quite a huge piece of software to an ExtJS Grid. Lots of data (and I mean lots of data) is loaded on-demand into spans that are placed inside grid's cells.
Imagine grid cells having <span id="foo_bar'></span> as content, and special ajax handlers are polling the backend for updated information and once available the spans are filled with it.
Now, in case I collapse some part of the grid and then re-exand them again I loose all automatically filled cell content, and am left with empty spans (which I started from in the first place).
I know the correct way is to setup a store and push all data into the store. But as I've mentioned above: I am porting quite a huge piece of legacy software to ExtJS, and I do not really have much choice here.
Is there a way to automagically push grid cell values to the store?
Update:
A grid is loaded with, suppose, 2000 cells (this can vary tremendously). Every cell contains various grades of HTML, mostly this is , but this can be pretty much anything (including several spans or divs in one cell). In the background there is a comet process pushing new data to the HTML page almost in real time. This data is populated to the corresponding SPANS and DIVs either based on their IDs or class or both.
What I want to achieve is that either:
a) the model for the grid is atomagically updated with the new html content of the cells (how can I achieve this)?
b) when collapsing/expanding tree's nodes the model data is NOT reloaded afresh.
Is either a or b possible? if so — how?
Just update your store when the 'special ajax handlers' successfully return values. In staid of manually messing with the dom.
so in the success callback do something like -> loadData()
Edit:
Seems like you are working with very bad legacy code :) If adding a simple line of code to the ajax handler is a tremendous effort.. You can however attach dom listeners, but it's very bad practice. Here are some events to listen to
Edit:
Here is an example of the use of how you could listen to dom events, it's rather a pure js solution but, meh.. it works..

Fastest way to append HTML content to a div using JavaScript

I have an HTML page that uses AJAX to retrieve messages from a server. I'm appending these messages to a as they are retrieved by setting its innerHTML property.
This works fine while the amount of text is small, but as it grows it causes Firefox to use all available CPU and the messages slow down to a crawl. I can't use a textbox, because I want some of the text to be highlighted in colour or using other HTML formatting. Is there any faster way to do this that wouldn't cause the browser to lock up?
I've tried using jQuery as well, but from what I've read setting .innerHTML is faster than its .html() function and that seems to be the case in my own experience, too.
Edit: Perceived performance is not an issue - messages are already being written as they are returned (using Comet). The issue is that the browser starts locking up. The amount of content isn't that huge - 400-500 lines seems to do it. There are no divs within that div. The entire thing is inside a table, but hopefully that shouldn't matter.
You specifically said that you were appending meaning that you are attaching it to the same parent. Are you doing something like:
myElem.innerHTML += newMessage;
or
myElem.innerHTML = myElem.innerHTML + newMessage;
because this is extremely inefficient (see this benchmark: http://jsben.ch/#/Nly0s). It would cause the browser to first do a very very large string concat (which is never good) but then even worse would have to re-parse insert and render everything you had previously appended. Much better than this would be to create a new div object, use innerHTML to put in the message and then call the dom method appendChild to insert the newly created div with the message. Then the browser will only have to insert and render the new message.
Can you break up your text and append it in chunks? Wrap portions of the text into div tags and then split them apart adding the smaller divs into the page.
While this won't speed the overall process, the perceived performance likely will be better as the user sees the first elements more quickly while the rest loads later, presumably off the visible page.
Additionally you probably should reconsider how much data you are sending down and embedding into the page. If the browser is slow chances are the amount of data is bound to be huge - does that really make sense to the user? Or would a paging interface (or other incremental load mechanism) make more sense?
You can use insertAdjacentHTML("beforeend", "<HTML to append>") for this.
Here is an article about its performance which has benchmarks showing insertAdjacentHTML is ~150x faster than the .innerHTML += operation. This might have been optimised by browsers in the years after the article was written though.
Going along with Rick's answer, why not just pass the info back as JSON, so you can just go through it, using setTimeout, and display perhaps 2-5 messages, then call setTimeout, then it will do the next batch, until the JSON array has been processed.
You should use innerHTML though, so your javascript can create that dynamically and add to the div, but, I would only do that for the first batch, to get everything up quickly.
After that I would go with cloning the first batch and changing the innerhtml for each of the other messages, along with other info, and add that to the dom tree.
Cloning will be faster than creating new elements and you won't have problems if anything else changes the dom tree while you are processing.
"The entire thing is inside a table, but hopefully that shouldn't matter."
Actually it matters alot. Due to the nature of tables a cell can often not be rendered until the width and height of all cells in the column and row are calculated. table-layout: fixed overcomes this at the cost of locking cell width and height based on the first row.
In short it may be best not to wrap in a table or if the data really is tabular try fixed layout rendering.
http://www.w3schools.com/Css/pr_tab_table-layout.asp
I wrote something similar, and it was challenging. First, you need to isolate the problem.
Is it the rendering code? Try commenting out all the rendering and see if the AJAX itself slows down Firefox. If so, try different approaches to the rendering, as outlined above.
Is it the network? Try commenting out the Ajax, and just run your innerHTML setting periodically. If this is the problem, you may need to experiment with different timing settings.

Categories

Resources