tags:

views:

310

answers:

4

I'm having issue with load speed using multiple jQuery binds on a couple thousands elements and inputs, is there a more efficient way of doing this?

The site has the ability to switch between product lists via ajax calls, the page cannot refresh. Some lists have 10 items, some 100, some over 2000. The issue of speed arises when I start flipping between the lists; each time the 2000+ item list is loaded the system drags for about 10 seconds.

Before I rebuild the list I am setting the target element's html to '', and unbinding the two bindings below. I'm sure it has something to do with all the parent, next, and child calls I am doing in the callbacks. Any help is much appreciated.

loop 2500 times

<ul>
  <li><input type="text" class="product-code" /></li>
  <li>PROD-CODE</li>
  ...
  <li>PRICE</li>
</ul>

end loop

$('li.product-code').bind( 'click', function(event){ 

    selector = '#p-'+ $(this).prev('li').children('input').attr('lm');

        $(selector).val(

            ( $(selector).val() == '' ? 1 : ( parseFloat( $(selector).val() ) + 1 ) )

        );

    Remote.Cart.lastProduct = selector;
    Remote.Cart.Products.Push( 

            Remote.Cart.customerKey, 
            { 
                code      : $(this).prev('li').children('input').attr('code'),
                title     : $(this).next('li').html(), 
                quantity  : $('#p-'+ $(this).prev('li').children('input').attr('lm') ).val(), 
                price     : $(this).prev('li').children('input').attr('price'),
                weight    : $(this).prev('li').children('input').attr('weight'),
                taxable   : $(this).prev('li').children('input').attr('taxable'),
                productId : $(this).prev('li').children('input').attr('productId'),
                links     : $(this).prev('li').children('input').attr('productLinks')
            },
            '#p-'+ $(this).prev('li').children('input').attr('lm'),
            false,
            ( parseFloat($(selector).val()) - 1 )

    );

    return false;

});

$('input.product-qty').bind( 'keyup', function(){ 

    Remote.Cart.lastProduct = '#p-'+ $(this).attr('lm');
    Remote.Cart.Products.Push( 

            Remote.Cart.customerKey, 
            { 
                code      : $(this).attr('code') , 
                title     : $(this).parent().next('li').next('li').html(), 
                quantity  : $(this).val(), 
                price     : $(this).attr('price'),
                weight    : $(this).attr('weight'),
                taxable   : $(this).attr('taxable'),
                productId : $(this).attr('productId'),
                links     : $(this).attr('productLinks')
            },
            '#p-'+ $(this).attr('lm'),
            false,
            previousValue
    );
});
A: 

you should look at jqrid or flexigrid somthing that will allow you to do paging thats allot of data to output at once so it's best to limit how much you put out at once even if those things are right for your project you must figure out how to limit the data is the bottom line

mcgrailm
Problem is I need all the data on one page based on customer request. I've already built a paging system, but went unused -_-
chelfers
+1  A: 

Bind your click event to the entire document, and within the function, look at event.target to see which product element was actually clicked on. This way you only need to do a single bind.

JacobM
A: 

First, use the profiler built into Firebug to check where most of the delay is; just hit "profile", run your slow action, hit it again and see which calls are the most expensive.

Second, look at "live" event handling: http://api.jquery.com/live/

The way this works is that there's just one event handler, looking at the whole document, delegating to live event handlers. This works much faster when you have loads of elements, because you don't need to add an event handler to each element specifically.

Alexander Malfait
I went with live handling. The profiler didn't help too much as it gave me a general sense of what I already knew was bogging the script down.
chelfers
+8  A: 

You are binding a handler 2500 times, instead make your function use either live or delegate like this:

$('li.product-code').live('click', function(event){ 
$('input.product-qty').live('keyup', function(){ 

.live() listens for the click to bubble up at the DOM level then executes the event with the context of the click source. This means you have one event handler instead of 2500 of them, meaning it's much faster and easier on the browser.

If you have a container that wraps the replaced content that isn't replaced (remains across all AJAX calls), you can make it more local like this:

$('#container').delegate('li.product-code', 'click', function(event){ 
$('#container').delegate('input.product-qty', 'keyup', function(){ 

The result of this is the event bubbles fewer times before being caught.

Another pain point is probably the creation of the elements, can you post that code? There are often easy optimizations that yield a big performance boost there.

Nick Craver
Live is the winner! Now my only speed hangup is a no-right-click plug-in I downloaded. Without the bindings the list creation was instant, now it is about a half second. With the no-right-click script it hangs, but that is due to the bindings I imagine. Thanks a lot!
chelfers
@chelfers - Which no-right-click plugin are you using? This should also be pretty easy to switch to `.live()` and get all your code instant...if you haven't done this already reply here and I'll take a look.
Nick Craver
`delegate()` is definitely the way to go. It's much more optimal than the alternatives when you have thousands of elements of which events you want to capture. The only caveat is that it requires jQuery 1.4.
asbjornu