2

I have a function that's running for 2-3 seconds on the client (no ajax calls). I'm trying to show a "Busy/Processing" animation while this operation is running.

simplified code is as followed:

var ajaxContainer = $('.spinner');
// show
$(ajaxContainer ).show();

// long operation
var items = GetItems();
$.each(items, function (index, value) {
    ProcessItem(value.itemID);
});

// hide
$(ajaxContainer ).hide();

but this does not work as expected. the result that i get is that the operation runs without showing the spinner. although it does show when the operation ends.

I saw some posts online mentioning that this could be done by using windows.setTimeout(). but since this operation is based on a dynamic number of items i would not want to set a specific timeout number in advance. instead i'd like to show the spinner when the operation starts, and hide it when it's finished.

is there an elegant way to achieve this?

kob490
  • 3,177
  • 4
  • 25
  • 40
  • 1
    Is your long operation synchronous or asynchronous? – Mike Bell Jul 31 '14 at 23:31
  • synchronous. It's basically a $.each() loop. – kob490 Jul 31 '14 at 23:32
  • Please post the code of the long operation. – Jimbali Jul 31 '14 at 23:35
  • 1
    If it's synchronous and blocking, all you have to do is show a spinner before the code executes, and remove on the line after ? – adeneo Jul 31 '14 at 23:38
  • As far as I know, a synchronous operation will always lock the UI (meaning the display won't update in the meantime). If you want the UI to stay interactive, you'll have to do something to make it asynchronous http://stackoverflow.com/questions/9516900/how-can-i-create-an-asynchronous-function-on-javascript (I've never tried this myself, otherwise I'd post it as an answer) – Mike Bell Jul 31 '14 at 23:38
  • I am too tired to make a proper answer, but the problem is that you are blocking the UI thread & thats why the spinner is not showing up. (You are not giving it time to be drawn!). If you want to make this properly you need to start using setTimeout yielding, which means that instead of blocking UI thread to 3 seconds, you execute your method in small chunks, such as 50ms at a time. See **yieldingEach** in this article http://fitzgeraldnick.com/weblog/35/ – Mauno Vähä Aug 01 '14 at 00:51

2 Answers2

2

I think you have to add a callback parameter to ProcessItem function in order to check if all items have been processed. Try this way:

function ProcessItem(id, callback){
    //do process and after call callback function 
    callback(); 
}

var processedItemsQuantity = 0;
var ajaxContainer = $('.spinner');
ajaxContainer.show();
// long operation
var items = GetItems();
$.each(items, function (index, value) {
    ProcessItem(value.itemID, function(){ 
        if (items.length - 1 == processedItemsQuantity){
            ajaxContainer.hide();
        } 
        else processedItemsQuantity++;
    });
});
Ragnar
  • 4,393
  • 1
  • 27
  • 40
  • I dont see how this solves the problem? So i dont understand the up-votes? obviously, all items is processed if same ajaxContainer.hide(); is called after the $.each method? I assume that the problem is not just hiding the container, because author said that "the result that i get is that the operation runs **without showing the spinner**. although it does show when the operation ends." – Mauno Vähä Aug 01 '14 at 10:28
  • @MaunoV. this is an asynchronous process, in this case you can't show the spinner after $.each method. If you do that, you will never see the spinner because it's hides too fast (the items are being processed yet). You have to hide the spinner after process the last item. – Ragnar Aug 01 '14 at 14:02
  • okey, well. Interested to hear comments from the author of this topic :). dunno if it works, I assumed that long operation was synchronous, I guess it was just a my mistake. – Mauno Vähä Aug 01 '14 at 14:49
0

You can't show a spinner in a synchronous operation because it's blocking the UI (ajax is asynchronous, that's why it works).

What you need is to put your code in a Web Worker.

Jaime Gómez
  • 6,961
  • 3
  • 40
  • 41