2

This question deals with concurrency issues, for suggestions on how to display a busy icon see this question: Javascript - loading/busy indicator or transparent div over page on event click

When a user initiates an AJAX request on a page it's useful to show some kind of "working" or busy icon or progress indicator. If there is only one long-running process this can be handled in a relatively straightforward way:

function do_action() {
   show_busy_icon();       

   long_running_asynchronous_process(function() {
      // Callback function run when process finishes
      hide_busy_icon();
   });
}

However, if multiple asynchronous processes are running on the page, using on/off methods wouldn't work. The first process to finish switches off the icon even though there are additional processes running.

So, how do you handle displaying an indicator, on a web page, that is on when there are one or more processes running, and off when there are no processes running?

I imagine it would be possible to maintain a count of the number of processes running. hide_busy_icon() only hides the icon if the process count is 0. That seems kinda prone to failure. Perhaps there's a better/simpler way that I'm not seeing.

Thanks for your ideas and suggestions!

Edit: After working with the solution in the marked answer for a while, I'm happy to say it works very well. The only issue I've run into are cases where my own scripts call functions of scripts I don't control. Unless those functions allow callbacks to be supplied there's no way to update the process-count when they begin and end.

An example of where this can occurs is adding a set of markers to a Google map. Once my script calls the Google maps function the busy icon disappears, while the markers are still being loaded.

I'm not sure of a good way to handle this.

Community
  • 1
  • 1
GloryFish
  • 13,078
  • 16
  • 53
  • 43

6 Answers6

8

If you want the same busy indicator for all actions, then use a counter.

Instead of "show_busy_icon()", do a "increment_busy_count()", which calls "show_busy_icon()" if busy count goes from 0 to 1. Instead of "hide_busy_icon()", do a "decrement_busy_count()", which calls "hide_busy_icon()" if busy count goes from 1 to 0.

Illandril
  • 656
  • 4
  • 11
1

I think the problem is really that you are using only one indicator. It may be easier to have an indicator for each action that needs one.

So, if you have multiple searches on a page each search area would have it's own independent indicator that is shown or hidden in the appropriate javascript functions.

1

Prototype has this built-in; a property called Ajax.activeRequestCount keeps track of how many requests are active at any given time. It'll also let you set up global Ajax responders to determine whether to hide or show the "busy" icon.

savetheclocktower
  • 1,443
  • 7
  • 12
0

I propose a different solution. this is not tested code, will probably not work, but is an illustration of the concept.

I assume the same excact action is not run in multiple instances. I do this to ensure that timeouts or similar problems in communication does not hang the indicator, but allows the indicator to be resolved when communication is re-established

 var actionRegister = new Array();

 function register_action(actionId)
 {
     show_busy_icon();       
     if(blockedTile.indexOf(actionId) != -1)
     {  // element already registered
        return;
     }
     actionRegister.push(actionId)
}


function unregister_action(actionId)
{
    var idx = blockedTile.indexOf(actionId);
    if(idx  != -1)
    {  
        actionRegister.splice(idx,1);
    }

    if(actionRegister.length < 1)
    {
       hide_busy_icon();
    }
}
Henrik
  • 2,180
  • 16
  • 29
0

We are all looking at it the wrong way. Ajax calls are used to load content using the XHR. This means that there has to be some predefined element in the entire DOM where the content is loaded. say we have an html of this type :

<html>
<body>
   <div id="content_1">
   </div>
   <div id="content_2">
   </div>
</body>
</html>

Using jQuery, say we want to load into content_1 and content_2 from content_1.php and content_2.php respectively.

Use the following script to handle the ajax::

$("content_1").html("<img src='loading.gif'>").load("http://samplesite.com/content_1.php");

$("content_2").html("<img src='loading.gif'>").load("http://samplesite.com/content_2.php");

This will place a loading gif in the respective divs and the gif will be later replaced by the loaded content from the php. Simple one line script. No counter required.

Requirement: any latest version of jQuery.

j0k
  • 22,600
  • 28
  • 79
  • 90
Rohan Bagchi
  • 649
  • 10
  • 17
0

Please see my answer here:

How to display a loading screen while site content loads

I give a small, working JavaScript example of how to do exactly this, hope it helps.

Community
  • 1
  • 1
mmattax
  • 27,172
  • 41
  • 116
  • 149
  • I don't think your example solves the issue.Say you had two urls: url1 and url2.url1 takes 1 sec to load and url2 takes 5 sec to load. Call load(url1) and load(url2) They both show the busy icon. – GloryFish Dec 09 '08 at 18:50
  • After 1 sec url1 returns a response and turns off the busy icon.You have 4 seconds where url2 is working but no icon is shown. – GloryFish Dec 09 '08 at 18:50