views:

99

answers:

5

I have an array of 2000 items, that I need to display in html - each of the items is placed into a div. Now each of the items can have 6 links to click on for further action. Here is how a single item currently looks:

<div class='b'>
  <div class='r'>
    <span id='l1' onclick='doSomething(itemId, linkId);'>1</span>
    <span id='l2' onclick='doSomething(itemId, linkId);'>2</span>
    <span id='l3' onclick='doSomething(itemId, linkId);'>3</span>
    <span id='l4' onclick='doSomething(itemId, linkId);'>4</span>
    <span id='l5' onclick='doSomething(itemId, linkId);'>5</span>
    <span id='l6' onclick='doSomething(itemId, linkId);'>6</span>
  </div>
  <div class='c'>
  some item text
  </div>
</div>

Now the problem is with the performance. I am using innerHTML to set the items into a master div on the page. The more html my "single item" contains the longer the DOM takes to add it. I am now trying to reduce the HTML to make it small as possible. Is there a way to render the span's differently without me having to use a single span for each of them? Maybe using jQuery?

+3  A: 

First thing you should be doing is attaching the onclick event to the DIV via jQuery or some other framework and let it bubble down so that you can use doSomething to cover all cases and depending on which element you clicked on, you could extract the item ID and link ID. Also do the spans really need IDs? I don't know based on your sample code. Also, maybe instead of loading the link and item IDs on page load, get them via AJAX on a as you need them basis.

My two cents while eating salad for lunch, nickyt

Update off the top of my head for vikasde . Syntax of this might not be entirely correct. I'm on lunch break.

$(".b").bind( // the class of your div, use an ID , e.g. #someID if you have more than one element with class b
    "click",
    function(e) { // e is the event object
     // do something with $(e.target), like check if it's one of your links and then do something with it.
    }
);
nickyt
I tried to use onDemand loading via ajax, however the managers decided that they need all of them in one shot on the page. How can I use jQuery to bubble down the click event?
vikasde
+1 for event delegation
gpilotino
I meant bubble up, not down.
nickyt
A: 

If you set the InnerHtml property of a node, the DOM has to interpret your HTML text and convert it into nodes. Essentially, you're running a language interpreter here. More text, more processing time. I suspect (but am not sure) that it would be faster to create actual DOM element nodes, with all requisite nesting of contents, and hook those to the containing node. Your "InnerHTML" solution is doing the same thing under the covers but also the additional work of making sense of your text.

I also second the suggestion of someone else who said it might be more economical to build all this content on the server rather than in the client via JS.

Finally, I think you can eliminate much of the content of your spans. You don't need an ID, you don't need arguments in your onclick(). Call a JS function which will figure out which node it's called from, go up one node to find the containing div and perhaps loop down the contained nodes and/or look at the text to figure out which item within a div it should be responding to. You can make the onclick handler do a whole lot of work - this work only gets done once, at mouse click time, and will not be multiplied by 2000x something. It will not take a perceptible amount of user time.

Carl Smotricz
Isn't innerHTML considered to be faster then appending?
vikasde
indeed, it is...
gpilotino
Well, what I could imagine is happening is that vikasde is doing something horrible like `innerHtml = innerHtml + anotherSpan`, repeatedly. So to get 6 spans, he's effectively building 21, 15 of them for the bit bucket. That's bound to be horrible, performance-wise. In a decent browser implementation, appending nodes, if done right, should be faster. The trick is to assemble the new stuff invisibly, so it doesn't trigger browser updates until done.
Carl Smotricz
@Carl: I am building the row in js and when i am done with the entire row, then I use innerHTML - I use that only once.
vikasde
Too bad, that would have been an easy optimization target! I stand corrected and egg-faced for the negative assumption.
Carl Smotricz
My next suggestion would then be to create all that content with a `display: none` class and switch the class to visible once you're done with all the building. If your browser is updating after every insertion, that's where your delay is coming from. It would also explain why (if) it gets slower the more rows you have.
Carl Smotricz
I did not think about that actually. Let me try that and see how it goes.
vikasde
This seems to work. Thanks. However now I notice that my browser reacts a bit slow. For example, when I move my mouse over a link, then I do not see the standard link cursor right away - it takes about 2-3 seconds, before I can see it and when I move the mouse out of the link, then it takes again 2-3 seconds, before I can see the standard mouse cursor. There is definitely a delay. Is there a way to fix this as well?
vikasde
With that much stuff in a buffer, your browser needs an oxygen tent and a pacemaker (that's my guess). You could check memory useage from the outside and make very sure your javascript doesn't leak memory (i.e. create objects and hang on to them longer than necessary). Can you try this page in various browsers?
Carl Smotricz
For us it needs to work in IE, since our company is standardized to it. I tested it in Firefox and it seems to work very smooth without any delays.
vikasde
Yeah, I thought you'd say that. I think this means the solution isn't bad, and residual problems are hard to combat because they're browser related. If you see any more chance to cut down on the complexity of the page, go for it! Also, one more possible solution coming up.
Carl Smotricz
I think the best would be to add the items to the DOM only for the visible area and remove all others and while scrolling add the new visible elements back to the DOM.
vikasde
Take a look at this: http://www.extjs.com/deploy/dev/examples/grid/buffer.html
vikasde
Super cool! Very impressive. You might be on to something here. But of course my latest suggestion is by far superior ;) Please see "Yet another Solution".
Carl Smotricz
A: 

John Resig wrote a blog on documentDragments http://ejohn.org/blog/dom-documentfragments/

My suggestion is to create a documentDragment for each row and append that to the DOM as you create it. A timeout wrapping each appendChild may help if there is any hanging from the browser

function addRow(row) {
    var fragment = document.createDocumentFragment();

    var div = document.createElement('div');
    div.addAttribute('class', 'b');

    fragment.appendChild(div);
    div.innerHtml = "<div>what ever you want in each row</div>";

    // setting a timeout of zero will allow the browser to intersperse the action of attaching to the dom with other things so that the delay isn't so noticable
    window.setTimeout(function() { 
        document.body.appendChild(div);
    }, 0);
};

hope that helps

Matt Smith
innerHTML still seems to be the fastest solution: http://www.quirksmode.org/dom/innerhtml.html
vikasde
You are right I've tested several of those methods but the most important thing in that script is the `setTimeout`. If you add each row one at a time then the page stays interactive while it adds the other rows. Another way to do it - if you could - is to add each row without the 6 zone markers then loop through them again once they are added to the DOM and add the appropriate zone markers - basically building the page up visually in bits.
Matt Smith
A: 

One other problem is that there's too much stuff on the page for your browser to handle gracefully. I'm not sure if the page's design permits this, but how about putting those 2000 lines into a DIV with a fixed size and overflow: auto so the user gets a scrollable window in the page?

It's not what I'd prefer as a user, but if it fixes the cursor weirdness it might be an acceptable workaround.

Carl Smotricz
I am already using that approach.
vikasde
A: 

Yet Another Solution

...to the "too much stuff on the page" problem:

(please let me know when you get sick and tired of these suggestions!)

If you have the option of using an embedded object, say a Java Applet (my personal preference but most people won't touch it) or JavaFX or Flash or Silverlight or...

then you could display all that funky data in that technology, embedded into your browser page. The contents of the page wouldn't be any of the browser's business and hence it wouldn't choke up on you.

Apart from the load time for Java or whatever, this could be transparent and invisible to the user, i.e. it's (almost) possible to do this so the text appears to be displayed on the page just as if it were directly in the HTML.

Carl Smotricz
I will consider this as well. I am trying to get my current approach to work.
vikasde
Maybe you can help me with this as well?http://stackoverflow.com/questions/1757106/find-top-and-last-element-inside-a-scrollable-div
vikasde