views:

220

answers:

5

In the example below, can anyone tell me how to make "slow response when clicked" respond more quickly without modifying appendContent()? I'm wondering if there's a way to place cheap operations before more expensive ones, and make sure the cheap ones actually get carried out quickly.

<div id="draw">slow response when clicked</div>

<div style="overflow: auto; height: 300px; border:solid 1px grey" id="content"></div>

<script language="javascript">

 var clickLink = document.getElementById("draw");
 var contentDiv = document.getElementById("content")

 function appendContent(){
  contentDiv.innerHTML =  contentDiv.innerHTML + "hello ";
 }

 clickLink.onclick = function(){
  clickLink.style.color = "red";
  for (var i = 0; i < 1500; i++){  
   appendContent(); 
  }
 };
</script>
A: 

since javascript don't have a good multithreading support, you need to split your dom operation into smaller parts. normally such things are done via performing long operation in the separate thread.

Eye of Hell
A: 

The Yahoo User Interface Library has a lot of good code and controls which already use technologies such as AJAX to improve your web application's perceived responsiveness.

Using a library such as Yahoo!'s will made adding this functionality to your application much faster and less error prone.

http://developer.yahoo.com/yui/

VBNight
+1  A: 

The mechanism for feedback should be different for the duration the user has to wait. Less than 0.1 seconds and a user will not notice.

Between 1 and 10 seconds you can simply display a symbol such as an animated gif of some sort that indicates your app is processing. See http://www.ajaxload.info/ I use a div with an ID "processing" and style it with a spinner and use the following jquery code to show and hide it before and after the process.

function showProcessing(){
    $("#processing").fadeIn("fast");
}

function hideProcessing(){
    $("#processing").fadeOut("fast");
}

Beyond 10 seconds it would be ideal to provide an estimate of processing time.

See Response Time Overview for the source of these numbers.

The following code immediately changes the link colour to red and calls the append method a fraction of a second later. Essentially is allows the browser to execute a separate thread before getting hung up in a loop. The timeout may need to be adjusted depending on the browser. Check out Neil Mix's Threading in JavaScript 1.7 if you need to relinquish control in a more generic manner.

    function startAppend(){
      for     (var i = 0; i < 1500; i++){             
              appendContent();        
      }
    }

    clickLink.onclick = function(){
            clickLink.style.color = "red";
            setTimeout('startAppend()', 10)                
    };
Michael Glenn
Thanks. By this point, the data is already in the browser, I'm just redrawing a table. My problem is that the redraw seems to interfere with my "processing" graphic. Settimeout helps, but not that much.
morgancodes
Edit the question to share the code and perhaps we can optimize.
Michael Glenn
Always a good idea, and done.
morgancodes
The code I added worked for me in FF3 on OSX.
Michael Glenn
Thanks Michael. That does indeed work. I've been doing something similar on my non-example page, but I'm still getting some delay. I'll check it out. Thanks for the confirmation that setTimout really should work.
morgancodes
Would chaining setTimouts be a viable option when doing a really large screen redraw? For example, draw a table 100 rows at a time? Any examples of this anywhere?
morgancodes
+1  A: 

If what you want to do is simply provide the user with some feedback so they know something's happening, you may try putting an animated gif - a loading circle or something, next to the button and disabling the button itself, then setting things back to normal after the redraw is complete.

Mussnoon
Thanks. I'm doing something like that already. The problem is there's a delay between the click and the appearance of the graphic.
morgancodes
A: 

Try this: add a div containing your loading graphic by default, but set the CSS to display:none. Then, when the div#draw is clicked, set the display of the loading graphic to block and then do your drawing. When the drawing is finished, set the display back to none.

VirtuosiMedia