Javascript - loading/busy indicator or transparent

2020-02-04 06:04发布

i got a client side javascript function which is triggered on a button click (basically, its a calculator!!). Sometimes, due to enormous data on the page, the javascript calculator function take to long & makes the page appear inactive to the user. I was planning to display a transparent div over entire page, maybe with a busy indicator (in the center) till the calculator function ends, so that user waits till process ends.

function CalculateAmountOnClick() {
  // Display transparent div

  // MY time consuming loop!
    {

    }

  // Remove transparent div 

}

Any ideas on how to go about this? Should i assign a css class to a div (which surrounds my entire page's content) using javascript when my calculator function starts? I tried that but didnt get desired results. Was facing issues with transparency in IE 6. Also how will i show a loading message + image in such a transparent div?

TIA

5条回答
不美不萌又怎样
2楼-- · 2020-02-04 06:32

I'm going to make some heavy assumptions here, but it sounds to me what is happening is that because you are directly locking the browser up with intense processing immediately after having set up the curtain element, the browser never has a chance to draw the curtain.

The browser doesn't redraw every time you update the DOM. It may woit to see if you're doing something more, and then draw what is needed (browsers vary their method for this). So in this case it may be refreshing the display only after it has removed the curtain, or you have forced a redraw by scrolling.

A fair waring: This kind of intense processing isn't very nice of you because it not only locks up your page. Because browsers generally implement only a single Javascript thread for ALL tabs, your processing will lock up all open tabs (= the browser). Also, you run the risk of the execution timeout and browser simply stopping your script (this can be as low as 5 seconds).

Here is a way around that.

If you can break your processing up into smaller chunks you could run it with a timeout (to allow the browser breathing space). Something like this should work:

function processLoop( actionFunc, numTimes, doneFunc ) {
  var i = 0;
  var f = function () {
    if (i < numTimes) {
      actionFunc( i++ );  // closure on i
      setTimeout( f, 10 )
    } 
    else if (doneFunc) { 
      doneFunc();
    }
  };
  f();
}

// add a curtain here
processLoop(function (i){
  // loop code goes in here
  console.log('number: ', i);
}, 
10,  // how many times to run loop
function (){
  // things that happen after the processing is done go here
  console.log('done!');
  // remove curtain here
});

This is essentially a while loop but each iteration of the loop is done in an timed interval so the browser has a bit of time to breathe in between. It will slow down the processing though, and any work done afterwards needs to go into a callback as the loop runs independently of whatwever may follow the call to processLoop.

Another variation on this is to set up the curtain, call your processing function with a setTimeout to allow the browser time to draw the curtain, and then remove it once you're done.

// add a curtain
var curtain = document.body.appendChild( document.createElement('div') );
curtain.id = "curtain";
curtain.onkeypress = curtain.onclick = function(){ return false; }
// delay running processing
setTimeout(function(){
  try {
    // here we go...
    myHeavyProcessingFunction();
  }
  finally {
    // remove the curtain
    curtain.parentNode.removeChild( curtain );
  }
}, 40);

If you are using a js-library, you may want to look at a ready made solution for creating curtains. These should exist for most libraries, here is one for jQuery, and they can help with the CSS.

查看更多
狗以群分
3楼-- · 2020-02-04 06:33

For the loading message, I would use a <div> with position:absolute, position it using left and top, and set the display to none.

When you want to show the loading indicator, you're going to have to use a timeout otherwise the div won't display until your processing is done. So, you should modify your code to this:

function showLoadingIndicator()
{
    // Display div by setting display to 'inline'
   setTimeout(CalculateAmountOnClick,0);
}

function CalculateAmountOnClick()
{
  // MY time consuming loop!
    {
    }
  // Remove transparent div 
}

Because you set the timeout, the page will redraw before the time-consuming loop happens.

查看更多
家丑人穷心不美
4楼-- · 2020-02-04 06:43

Javacript to show a curtain:

function CalculateAmountOnClick () {
  var curtain = document.body.appendChild( document.createElement('div') );
  curtain.id = "curtain";
  curtain.onkeypress = curtain.onclick = function(){ return false; }
  try {
    // your operations
  }
  finally {
    curtain.parentNode.removeChild( curtain );
  }
}

Your CSS:

#curtain {
  position: fixed;
  _position: absolute;
  z-index: 99;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  _height: expression(document.body.offsetHeight + "px");
  background: url(curtain.png);
  _background: url(curtain.gif);
}

(Move MSIE 6 underscore hacks to conditionally included files as desired.)

You could set this up as add/remove functions for the curtain, or as a wrapper:

function modalProcess( callback ) {
  var ret;
  var curtain = document.body.appendChild( document.createElement('div') );
  curtain.id = "curtain";
  curtain.onkeypress = curtain.onclick = function(){ return false; }
  try {
    ret = callback();
  }
  finally {
    curtain.parentNode.removeChild( curtain );
  }
  return ret;
}

Which you could then call like this:

var result = modalProcess(function(){
  // your operations here
});
查看更多
萌系小妹纸
5楼-- · 2020-02-04 06:46

In addition to all of the above, don't forget to put an invisible iframe behind the shim, so that it shows up above select boxes in IE.

Edit: This site, although it provides a solution to a more complex problem, does cover creating a modal background. http://www.codeproject.com/KB/aspnet/ModalDialogV2.aspx

查看更多
乱世女痞
6楼-- · 2020-02-04 06:51

I would do something like:

  1. unhide a div (display:inline)
  2. make the position:absolute
  3. give it a z-index:99
  4. make the height and width 100%
  5. when the processing is done set display:none

To make it transparent you'll have to set the opacity which is different in Firefox, IE, etc.

To show a loading icon you can always create a second div and position it where you want to on the page. When it's done loading, remove it along with the transparent one.

查看更多
登录 后发表回答