防止javascript调用延迟外观

时间:2014-12-18 20:47:18

标签: javascript ajax

我有一个问题,即在进行通话时没有出现简单的视觉效果,而是大幅延迟,直到它没有实际意义。

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

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

最后但是至少,如果我在数据获取之前引入了对alert()的调用,那么可视化的东西都会在警报响起时发生,它不会等到数据完成后才会发生。

这是代码。再次注意,数据get是对$ .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

提前致谢...

2 个答案:

答案 0 :(得分:0)

这是我推荐的。完全不需要使用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调用完成后运行。我想不出有任何其他有效理由这样做。

答案 1 :(得分:0)

浏览器将尝试每n ms进行一次重绘,如果浏览器在该时间点被阻塞(调用堆栈不为空),它将等待堆栈为空渲染。在您的情况下,您将显示微调器,发送同步ajax请求,然后隐藏微调器。这意味着在显示微调器和隐藏微调器之间,callstack永远不会清空,因此浏览器永远不会重新绘制,因此在浏览器渲染之前隐藏了微调器。

要解决此问题,您需要将阻止的代码段移出堆栈,以便在浏览器被阻止之前进行浏览器渲染。这通常使用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()));
  });
}