运行后台脚本时延迟 javascript DOM 更改

Delaying javascript DOM change when running background script

提问人:danbae 提问时间:1/26/2023 最后编辑:danbae 更新时间:1/26/2023 访问量:47

问:

我正在编写一个脚本,该脚本有时涉及在渲染结果之前进行许多耗时的计算,有时只是几个。为了通知用户正在发生延迟,在计算过程中会显示一个“手表”符号。目前为止,一切都好。但是,如果延迟很短,我不希望显示手表,因为符号的重复短暂闪烁可能会令人讨厌。我不能用来延迟手表的显示,因为在顺序计算操作完成之前,该功能无法结束。

在阅读 SO 时,我发现建议使用 Web Worker 来获取计算操作的异步行为。但是,即使将计算委托给 Web Worker,手表的闪烁行为仍然存在。同样,不能用于延迟手表的渲染,因为在延迟结束之前就完成了快速操作。作为最后的手段,我使用延迟方法,这很有效。但使用起来似乎不那么优雅.有没有更方便的方法来实现这一目标?

下面是一个带有脚本和 WebWorker 演示的 html 页面,分别显示了各种方法在长操作和短操作期间的行为,其中第三个在我手中给出了所需的结果。您可以通过注释掉其他内容在它们之间切换。

main.html
setTimeout()setTimeout()fadeIn()fadeIn()

<!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>

异步工作者.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");
});
JavaScript jQuery 异步 Web 辅助角色

评论

2赞 A_A 1/26/2023
我不确定我是否理解为什么你不能使用 .对于工作在超时之前完成的情况,您可以简单地取消超时,它不会显示任何内容(参见 clearTimeout),或者在回调中检查操作是否已经完成(通过检查跟踪操作状态的变量)setTimeout

答:

0赞 danbae 1/26/2023 #1

正如@A_A所建议的,解决方案是在计算完成时使用并清除超时。也许这很明显,但只要版主不介意,我就会保留这个问题。setTimeout()

来自 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();
});