setTimeout被连续的AJAX请求阻止了吗?

时间:2015-02-12 10:43:53

标签: javascript ajax settimeout

我在使用setTimeout通知后端保持会话活动的Web应用程序上修复了一个问题。除了以下情况之外,这在所有方案中都按预期工作:

当有背靠背同步AJAX帖子发生时,setTimeout没有触发。

据我所知,setTimeout触发可能会延迟JavaScript is single-threaded,并且必须等待一项任务完成。

我的问题是:为什么setTimeout根本没有触发?为什么它会在所有AJAX请求结束时触发而不是在它们之间?

这是我的keepAlive功能

function keepAlive() {
    var img = new Image(1, 1);
    img.src = "google.com" + '?' + new Date();

    timer = setTimeout(function () {
        keepAlive();
    }, 10000);
}

我在jsfiddle中创建了一个快速而肮脏的问题demo

提前致谢!

2 个答案:

答案 0 :(得分:3)

  

当有背靠背同步AJAX帖子发生时,setTimeout没有触发。

     

...

     

我的问题是:为什么setTimeout根本没有触发?为什么它会在所有AJAX请求结束时触发而不是在它们之间?

因为他们是同步请求。这是不使用同步请求的众多原因之一;改为使用异步请求。

当ajax请求是同步的时,它就像一个函数调用:它占用主UI线程。所以:

doThisSyncRequest();
doThatSyncRequest();
doTheOtherSyncRequest();

上面没有任何一点,线程会回到空闲状态并查看其排队的工作,因此排队的setTimeout回调无法运行。

主UI线程通过任务队列工作:

  1. 任务队列为空时空闲

  2. 当某些事情发生时("事件"在一般意义上,包括计时器到期,新代码被添加等),浏览器将一个任务与主要的相关JavaScript代码排队用于获取的UI线程

  3. 当主UI线程选择任务时,它会运行相关代码不间断

  4. 如果在代码运行时发生其他事情,浏览器会为这些事件排队任务并在队列中等待

  5. 当主UI线程完成一个任务的代码运行时,它会从队列中获取下一个任务(如果有的话)或者回到空闲状态

  6. 由于同步请求会占用线程,因此当它们正在运行时它会停留在#3中,并且其他任何内容都会排队。

    当您使用异步请求时,启动它们的JavaScript代码在它们运行时不会被阻止;相反,代码流继续并完成,主UI线程可以继续处理后续任务。最终异步请求的状态发生变化(例如,它完成),该任务将任务排队以调用就绪状态变化回调。

    我建议使用异步请求,原因有多种,包括同步请求会导致用户体验不佳,因为UI会在请求期间锁定。但只是为了完整性,你确实有另一种选择:你可以移动那个后台ajax调用来保持会话活着进入web worker线程。然后,由于它在不同的线程上运行,因此主UI线程上的同步ajax调用不会阻止它运行。我没有推荐这个(我建议使用异步请求),只是将其标记为选项。所有现代桌面浏览器(但不是IE9及更早版本)中的网络工作者are supported,移动支持正在改进,并且很容易通过功能检测它们是否得到支持并重新使用主要UI线程,如果没有。但实际上,异步请求是可行的方法。

答案 1 :(得分:1)

正如您所提到的,Ajax调用是同步的,这可能会让您的setTimeout被触发。您可以通过使Ajax调用异步来尝试此操作。

由于