jQuery show "loading" during slow operation

The Disintegrator picture The Disintegrator · Aug 10, 2009 · Viewed 18.4k times · Source

I'm trying to show a small loading image during a slow operation with jQuery and can't get it right. It's a BIG table with thousands of rows. When I check the "mostrarArticulosDeReferencia" checkbox it removes the "hidden" class from these rows. This operation takes a couple of seconds and I want to give some feedback. "loading" is a div with a small animated gif

Here's the full code

jQuery(document).ready(function() {
jQuery("#mostrarArticulosDeReferencia").click(function(event){
    if( jQuery("#mostrarArticulosDeReferencia").attr("checked") ) {
        jQuery("#loading").show(); //not showing
        jQuery("#listadoArticulos tr.r").removeClass("hidden"); //slow operation
        jQuery("#loading").hide();
    } else {
        jQuery("#loading").show();  //not showing
        jQuery("#listadoArticulos tr.r").addClass("hidden");  //slow operation
        jQuery("#loading").hide();
    }
});
jQuery("#loading").hide();
});

It looks like jquery is "optimizing" those 3 lines

        jQuery("#loading").show(); //not showing
        jQuery("#listadoArticulos tr.r").removeClass("hidden");
        jQuery("#loading").hide();

And never shows the loading div. Any Ideas?

Bonus: There is a faster way of doing this show/hide thing? Found out that toggle is WAY slower.

UPDATE: I tried this

    jQuery("#mostrarArticulosDeReferencia").click(function(event){
    if( jQuery("#mostrarArticulosDeReferencia").attr("checked") ) {
            jQuery("#loading").show(); //not showing
            jQuery("#listadoArticulos tr.r").removeClass("hidden"); //slow operation
            setTimeout("jQuery('#loading').hide()", 1000);
    } else {
            jQuery("#loading").show();  //not showing
            jQuery("#listadoArticulos tr.r").addClass("hidden");  //slow operation
            setTimeout("jQuery('#loading').hide()", 1000);
    }
});

That's what I get

  1. click on checkbox
  2. nothing happens during 2/3 secs (processing)
  3. page gets updated
  4. loading div shows up during a split second

UPDATE 2: I've got a working solution. But WHY I have to use setTimeout to make it work is beyond me...

    jQuery("#mostrarArticulosDeReferencia").click(function(event){
    if( jQuery("#mostrarArticulosDeReferencia").attr("checked") ) {
            jQuery("#loading").show();
            setTimeout("jQuery('#listadoArticulos tr.r').removeClass('hidden');", 1);
            setTimeout("jQuery('#loading').hide()", 1);
    } else {
            jQuery("#loading").show();
            setTimeout("jQuery('#listadoArticulos tr.r').addClass('hidden');", 1);
            setTimeout("jQuery('#loading').hide()", 1);
    }
});

UPDATE 3: Just found a better solution for this particular case.

//mostrar u ocultar articulos de referencia
$("#mostrarArticulosDeReferencia").click(function(event){
    if( $("#mostrarArticulosDeReferencia").attr("checked") )
        $("tr.r").css({'display':'table-row'});
    else
        $("tr.r").css({'display':'none'});
});

Using .css({'display':'none'}) turns out to be WAY faster than hide(), so no need for the loading animation...
This article showed me the light: show/hide performance.

Answer

The Disintegrator picture The Disintegrator · Sep 20, 2009

I tried everything and I have to conclude than this is the product of a browser brainfart.

  1. jQuery tells the browser to show/hide the loading div
  2. jQuery tells the browser to add/remove the hidden class from the rows
  3. jQuery tells the browser to show/hide the loading div
  4. The browser does all the above steps in the wrong order (2 in first place)

'setTimeout' in my last update is forcing the browser tho execute all the steps in the correct order. It sucks, isn't elegant, but at least it works...

Update: the setTimeout is necessary because jquery "simplifies" the chain of commands. If I tell it to hide one element and the show it again, it will simply ignore the command because the final result will be the same as do nothing...