防止 JavaScript 调用延迟出现

prevent javascript calls from having delayed appearance

本文关键字:延迟 调用 JavaScript 防止      更新时间:2023-09-26

我遇到了问题,即在拨打电话时没有出现简单的视觉效果,而是被大大延迟,几乎直到它没有实际意义。

我正在尝试同步获取一些数据(是的,没错,不是异步的(,在它发生时放置一个"等待"指示器,然后在获取完成后隐藏指示器。问题是执行执行该指标的代码时没有出现;jQuery show(( 调用的可视结果在调用发生时不会发生 - 它会等到数据获取完成。我已经通过将时间戳记录到控制台来确认 show(( 调用确实在数据获取之前发生。

奇怪的是,控制台日志记录在视觉上也会延迟,即使时间戳确认代码正在发生

最后但并非最不重要的一点是,如果我在数据获取之前引入对 alert(( 的调用,那么视觉内容都会在警报上升时发生,它不会等到数据获取完成。

这是代码。再次注意,数据获取是对 $.ajax(( 的同步调用(即 async: false(。

fillInClient: function(clientId) {
  var result, spinner;
  console.log("spinning at " + ($.now()));
  spinner = $("tr#client_" + clientId + " .spinner");
  spinner.show();
  // if I call alert("foo") here, I see both of the spinner.show() and 
  // the first console.log immediately. Then after a few seconds, 
  // I see the hide, and the second console.log
  // Without alert(), I never see the show() and the first console.log
  // doesn't appear until after this:
  // this takes several seconds
  result = $.ajax({
    type: "GET",
    url: "/advisor/householding/accounts?user=" + clientId,
    async: false
  });  
  spinner.hide();
  console.log("stopping at " + ($.now()));
  return result;
}

这是我在控制台中看到的内容。请注意,它们有效地同时出现,但您可以从时间戳中看到它们被调用间隔几秒钟。

spinning at 1418933857688
stopping at 1418933862374

提前感谢...

浏览器将尝试每n毫秒重新绘制一次,如果浏览器在该时间点被阻止(调用堆栈不为空(,它将等到堆栈为空进行渲染。在本例中,你显示微调器,发送同步 ajax 请求,然后隐藏微调器。这意味着在显示微调器和隐藏微调器之间,调用堆栈永远不会清空,因此浏览器永远不会重新绘制,因此在浏览器呈现微调器之前,您的微调器是隐藏的。

要解决此问题,您需要将阻塞的代码段移出堆栈,以便在浏览器被阻止之前进行浏览器渲染。这通常是使用 setTimeout 来完成的,但是,这将完全破坏您的代码的工作方式,以至于它可能是一个异步请求。以下是您的代码仍在使用 setTimeout 的同步请求:

fillInClient: function(clientId, doneCallback) {
  var result, spinner;
  console.log("spinning at " + ($.now()));
  spinner = $("tr#client_" + clientId + " .spinner");
  spinner.show();
  setTimeout(function () {
    var result = $.ajax({
      type: "GET",
      url: "/advisor/householding/accounts?user=" + clientId,
      async: false
    });
    doneCallback && doneCallback(result);
    spinner.hide();
    console.log("stopping at " + ($.now()));
  }, 20);
  //return result;
}

如您所见,您的函数不再返回结果,而是必须进行回调。此时,您不妨将其设置为异步请求并丢失setTimeout

fillInClient: function(clientId, doneCallback) {
  var result, spinner;
  console.log("spinning at " + ($.now()));
  spinner = $("tr#client_" + clientId + " .spinner");
  spinner.show();
  $.ajax({
    type: "GET",
    url: "/advisor/householding/accounts?user=" + clientId
  })
  .done(doneCallback)
  .always(function () {
    spinner.hide();
    console.log("stopping at " + ($.now()));
  });
}

这是我的建议。 对同步请求使用 AJAX 是完全没有必要的。 若要为异步代码提供同步感觉,请使用回调。 下面是一个示例:

fillInClient: function(clientId) {
    var result, spinner;
    console.log("spinning at " + ($.now()));
    spinner = $("tr#client_" + clientId + " .spinner");
    spinner.show();
    result = $.ajax({
        type: "GET",
        url: "/advisor/householding/accounts?user=" + clientId,
        complete: function (){
            spinner.hide();
            console.log("stopping at " + ($.now()));
            //Other logic to run after the call completes
        }
    });
}

因此,您在同步函数之后拥有的所有内容,我已移至complete()函数,因此它只会在 AJAX 调用完成后运行。 我想不出任何正当的理由以另一种方式做到这一点。