【问题标题】:setTimeout blocked by continuous AJAX requests?setTimeout 被连续的 AJAX 请求阻塞?
【发布时间】:2015-02-12 10:43:53
【问题描述】:

我正在修复一个使用 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

提前致谢!

【问题讨论】:

  • JavaScript 不是单线程的。 浏览器上的 JavaScript 有一个 主 UI 线程(以及任意数量的 Web 工作线程)。
  • 谢谢@T.J.Crowder!我的立场是正确的:)

标签: javascript ajax settimeout


【解决方案1】:

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

...

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

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

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

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

在上述任何时候,线程都不会返回空闲状态并查看其排队的工作,因此排队的 setTimeout 回调无法运行。

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

  1. 任务队列为空时空闲

  2. 当发生某些事情(一般意义上的“事件”,包括计时器到期、添加新代码等)时,浏览器会将任务与相关的 JavaScript 代码排入队列,以供主 UI 线程处理

  3. 当主 UI 线程接到一个任务时,它会运行相关的代码不间断

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

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

由于同步请求占用了线程,因此在它们运行时它会停留在#3,并且其他任何东西都会排队。

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

出于多种原因,我建议使用异步请求,其中包括同步请求会导致用户体验不佳,因为 UI 在请求期间会锁定。但为了完整起见,您确实有另一种选择:您可以将后台 ajax 调用移动到 web worker 线程中以保持会话活动。然后,由于它在不同的线程上运行,主 UI 线程上的同步 ajax 调用不会阻止它运行。我不推荐这个(我建议改用异步请求),只是将其标记为一个选项。 Web worker are supported 在所有现代桌面浏览器(但不包括 IE9 和更早版本)中,移动支持正在改进,并且很容易检测它们是否受支持,如果不支持则回退到使用主 UI 线程。但实际上,异步请求是可行的方法。

【讨论】:

  • 感谢您的详细解释!但我面临的问题是这些请求必须是同步的,因为更改它会破坏我之前提到的 Web 应用程序的某些功能。我将研究使用 Web Worker 的可能性,因为我们的一些客户仍在使用 IE8。
  • @AwadMaharoof:Ajax 调用永远不必是同步的,onbeforeunload 是一个例外,我认为这根本不是您应该使用 ajax 的时候。在其他任何地方,这只是正确使用异步请求的问题。
  • 这些ajax调用上传图片。这些图像按顺序上传并且服务器始终知道图像数量至关重要。是否有可能在这样的场景中使用异步 ajax 调用?
  • @AwadMaharoof:“按顺序上传这些图像至关重要” 为什么?而不是伴随他们的时间戳说他们什么时候开始,或者类似的? “...并且服务器始终知道图像计数。”嗯,它会,无论顺序或同步与异步如何。
【解决方案2】:

正如您提到的,Ajax 调用是同步的,这可能会阻止您的 setTimeout 触发。你可以通过让你的 Ajax 调用异步来试试这个。

谢谢

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 2014-07-29
    • 2019-11-04
    相关资源
    最近更新 更多