简体   繁体   中英

Delaying javascript DOM change when running background script

I am working on a script that sometimes involves many time-consuming calculations to occur before rendering the result, sometimes just a few. To inform the user that the delay is occurring, a "wristwatch" symbol is shown during the calculation. So far so good. But I don't want the wristwatch to be shown if the delay is very short, as the repeated brief flashing of the symbol can be annoying to view. I can't use setTimeout() to delay the display of the wristwatch since that function can't conclude until the sequential calculation operations are completed.

Reading up here on SO, I found that a Web Worker was advisable to use to get asynchronous behaviour of the calculation operations. But even when relegating the calculations to a Web Worker, the flashing behaviour of the wristwatch persisted. Again, setTimeout() couldn't be used to delay the rendering of the watch, as the quick operations were completed before the delay was over. As a last resort, I used fadeIn() as a delay method, which worked. But it seems less than elegant to use fadeIn() . Is there a more convenient way to achieve this goal?

Below are the html page with script and WebWorker of a demo that show the behaviour during long and short operations, respectively, of the various methods, of which the third gives the desired result in my hands. You can switch between them by commenting out the others.

main.html

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
jQuery(function($){
  const worker = new Worker("asyncWorker.js");
  $("#shortbtn,#longbtn").click(function(){
    $("#done").hide();

    /* METHOD 1 */
    setTimeout(function(){
      $("#wait").show();
    },100);

    /* METHOD 2 */
    //$("#wait").show();

    /* METHOD 3 */
    //$("#wait").fadeIn(100);

    let btnId = $(this).attr("id");
    worker.postMessage(btnId);
    worker.addEventListener("message",function(message){
      $("#wait").hide();
      $("#done").show();
    });
  });
})
</script>
<style>
  #wait,#done{display:none;}
  #wait{font-size: 4em;}
</style>
</head>
<body>
  <button id="shortbtn">Short delay</button>&nbsp;&nbsp;&nbsp;
  <button id="longbtn">Long delay</button>
  <div id="div">
    <span id="wait">&#8986;</span>
    <span id="done">Done!</span>
  </div>
</body>
</html>

asyncWorker.js

addEventListener("message",function(message){
  switch(message.data){
    case "shortbtn":
      for(let i=0;i<1000;i++){let a = 0;}// simulate quick process
    break;
    case "longbtn":
      for(let i=0;i<3*1e9;i++){let a = 0;} // simulate slow process
    break;
  }
  postMessage("done");
});

As suggested by @A_A, the solution is to use setTimeout() and clear the timeout when the calculation is finished. Maybe that is rather obvious, but I'll keep the question as long as the moderators don't mind.

From main.html:

/* METHOD 4 */
let tmo = setTimeout(function(){
  $("#wait").show();
},250);


let btnId = $(this).attr("id");
worker.postMessage(btnId);
worker.addEventListener("message",function(message){
  clearTimeout(tmo); // prevents overdue timeout
  $("#wait").hide();
  $("#done").show();
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM