views:

640

answers:

5

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.

+1  A: 

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?

Rick Strahl
A: 

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.

James Black
+1  A: 

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. 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.

Russell Leggett
Yes, I was doing that. I ended up calling myDiv.append() for some bits of text, which I knew were single lines enclosed in <p> tags, but still using string concatenation and assigning .innerHTML for other parts where a lot of text inside <pre> tags is sent over multiple messages.
Evgeny
A: 

"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%5Ftab%5Ftable-layout.asp

SpliFF
A: 

I wrote something similar, and it was challenging. First, you need to isolate the problem.

  1. 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.

  2. 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.

ndp
It is the rendering. If I make the AJAX calls without displaying any text it's fine. In fact, if I replace the div contents with the last received bit of text instead of appending it to the existing text it's also fine.
Evgeny