【问题标题】:why does the browser freeze when executing many ajax requests?为什么在执行许多 ajax 请求时浏览器会死机?
【发布时间】:2012-02-22 15:38:36
【问题描述】:

我有一个页面正在使用 jquery.load 执行大约 200 个 ajax 请求,但它的行为非常非 ajax 方式,因为在获取结果时浏览器被冻结。

冻结是指失去对浏览器的控制,甚至无法上下滚动。然后在完成所有请求后立即显示所有结果,但我知道它实际上是通过查看目标服务器的访问日志一次获取 6 个结果(浏览器控制的“同一主机”策略)。

虽然 jquery.load 命令是使用“foreach”循环构建的,但它们在用户加载页面时已经写入页面的源代码(因此出于所有意图和目的,它们都可以单独手写),所以它不像页面正在等待循环完成。最后一个“症状”是,即使只有 30 个请求,问题也是一样的。

所以这对我来说很奇怪,我正在寻找可能导致此问题的原因以及如何解决它的想法。这肯定会让最终用户感到困惑,尤其是因为它可能需要 90-100 秒才能返回所有响应并且用户重新获得对浏览器的控制权。

一个小更新:

我在另一个 web 应用程序中运行了非常相似的代码,它同时执行大约 20 个请求而没有问题。不同之处在于,它不是获取页面,而是通过 ssh 连接到服务器并通过脚本读取/更新文件系统上的文件。我原以为这实际上会产生更多开销,但它没有这些问题。

正如我所说 - 即使是 20 个请求也会导致相关代码出现同样的问题......所以我很想认为它可能与 curl 相关......尽管它纯粹是猜测。

现在更大的更新,包含无限多的代码!!!

应用程序更完整的背景是这样的。我们运行一个由世界上一些流量最高的 WebSphere AppServer 组成的集群,它们正在运行我们的 Commerce 应用程序。流量的强度意味着,如果我们只是在 JVM 预热之前让流量进入应用服务器,它们就会崩溃!因此,我们在允许流量打开之前点击了几个关键页面,因为这会预编译所有主要的 servlet,按比例分配 JVM,并填充一些 servlet 缓存。然后流量可以毫无问题地进入服务器并且运行良好。

我们有一个用 CGI 编写的应用程序版本,它可以运行,但由于是同步的,所以速度很慢。我们正在谈论在某些集群上运行 10 分钟。由于是同步请求,所以只使用了appserver上的一个线程和一个jdbc连接。

所以新的 webapp 所做的就是使用这些关键页面的模板,结合一堆市场定义(国家代码、语言代码、目录 ID 等)来生成所有需要点击的 URL 的列表.通过以异步方式访问它们,它不仅运行速度更快(现在只需 90 秒),它还可以更好地分配 JVM,使用多达 30 个线程并将 JDBC 池打开到其全部连接数。因此,当我们让流量继续运行时,它真的处于类似生产的状态。所以我对结果非常满意,但是从纯粹的装饰和解决难题的角度来看,这种浏览器冻结让我很恼火。

所以现在一些代码,用户只需选择一个应用服务器,应用决定它来自哪个集群,并显示它将命中的计算 URL 列表。此时页面是一个“Markets x Urls”表,每个单元格都有一个唯一的 id,jquery 使用该 ID 将正确的结果放在正确的单元格中(因为我们不能保证结果返回的顺序 -我们也不想这样做,因为这会让我们再次回到同步领域。

因此,在用户准备好单击 Go 时,表格已写入并准备好 jQuery 命令。单击 go 时,jquery 脚本被执行,URL 被命中并为每个返回一个 HTTP 状态代码,所以我们知道它们是成功的。

生成的 JQ 部分看起来像(缩短为几个市场)

$("a#submit").click(function(event) {
    alert(" booya ");
    $("#sesv-1").load("psurl.php?server=servera.domain.com&url=/se/sv");
    $("#sesv-2").load("psurl.php?server=servera.domain.com&url=/se/sv/catalog/productsaz/");
    $("#sesv-3").load("psurl.php?server=servera.domain.com&url=/se/sv/catalog/products/12345678");
    $("#sesv-4").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?storeId=14&productId=103406&StoreNumber=099&langId=-13&ddkey=http:StockSearch");
    $("#sesv-5").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?query=testProd&storeId=14&langId=-11&StoreNumber=011");
    $("#atde-1").load("psurl.php?server=servera.domain.com&url=/at/de");
    $("#atde-2").load("psurl.php?server=servera.domain.com&url=/at/de/catalog/productsaz/");
    $("#atde-3").load("psurl.php?server=servera.domain.com&url=/at/de/catalog/products/12345678");
    $("#atde-4").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?storeId=1&productId=103406&StoreNumber=114&langId=-99&ddkey=http:StockSearch");
    $("#atde-5").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?query=testProd&storeId=1&langId=-21&StoreNumber=273");
    $("#benl-1").load("psurl.php?server=servera.domain.com&url=/be/nl");
    $("#benl-2").load("psurl.php?server=servera.domain.com&url=/be/nl/catalog/productsaz/");
    $("#benl-3").load("psurl.php?server=servera.domain.com&url=/be/nl/catalog/products/12345678");
    $("#benl-4").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?storeId=18&productId=103406&StoreNumber=412&langId=-44&ddkey=http:StockSearch");
    $("#benl-5").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?query=testProd&storeId=18&langId=-23&StoreNumber=482");
    $("#befr-1").load("psurl.php?server=servera.domain.com&url=/be/fr");
    $("#befr-2").load("psurl.php?server=servera.domain.com&url=/be/fr/catalog/productsaz/");
    $("#befr-3").load("psurl.php?server=servera.domain.com&url=/be/fr/catalog/products/12345678");
    $("#befr-4").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?storeId=130&productId=103406&StoreNumber=048&langId=-73&ddkey=http:StockSearch");
    $("#befr-5").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?query=testProd&storeId=130&langId=-24&StoreNumber=482");
    $("#caen-1").load("psurl.php?server=servera.domain.com&url=/ca/en");
    $("#caen-2").load("psurl.php?server=servera.domain.com&url=/ca/en/catalog/productsaz/");
    $("#caen-3").load("psurl.php?server=servera.domain.com&url=/ca/en/catalog/products/12345678");
    $("#caen-4").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?storeId=30&productId=103406&StoreNumber=006&langId=-11&ddkey=http:StockSearch");
    $("#caen-5").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?query=testProd&storeId=30&langId=-15&StoreNumber=216");
    $("#cafr-1").load("psurl.php?server=servera.domain.com&url=/ca/fr");
    $("#cafr-2").load("psurl.php?server=servera.domain.com&url=/ca/fr/catalog/productsaz/");
    $("#cafr-3").load("psurl.php?server=servera.domain.com&url=/ca/fr/catalog/products/12345678");
    $("#cafr-4").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?storeId=33&productId=103406&StoreNumber=124&langId=-09&ddkey=http:StockSearch");
    $("#cafr-5").load("psurl.php?server=servera.domain.com&url=/webapp/wcs/stores/servlet/StockSearch?query=testProd&storeId=33&langId=-16&StoreNumber=216")
    });
});

PS URL 只是一个 curl 请求函数,响应 404、200、500 等,然后用于填充相关单元格。

function getPage( $url ) {
$options = array(
    CURLOPT_URL             => $url,
    CURLOPT_RETURNTRANSFER => true,                 // return web page
    CURLOPT_HEADER         => true,                 // return headers
    CURLOPT_FOLLOWLOCATION => true,                 // follow redirects
    CURLOPT_ENCODING       => "",                   // handle all encodings
    CURLOPT_USERAGENT      => "pre-surf",           // who am i
    CURLOPT_AUTOREFERER    => true,                 // set referer on redirect
    CURLOPT_CONNECTTIMEOUT => 120,                  // timeout on connect
    CURLOPT_TIMEOUT        => 120,                  // timeout on response
    CURLOPT_MAXREDIRS      => 10,                   // stop after 10 redirects
    CURLOPT_POST            => 0,                   // i am not sending post data
    CURLOPT_SSL_VERIFYHOST => 0,                    // don't verify ssl
    CURLOPT_SSL_VERIFYPEER => FALSE,                //
);

$ch      = curl_init();
curl_setopt_array($ch, $options);
$content = curl_exec($ch);
$err     = curl_errno($ch);
$errmsg  = curl_error($ch) ;
$header  = curl_getinfo($ch);
curl_close($ch);

//  $header['errno']   = $err;
//  $header['errmsg']  = $errmsg;
//  $header['content'] = $content;
return $header['http_status_code'];
}

【问题讨论】:

  • “200 个 ajax 请求”这就是原因。
  • 200 个 ajax 请求等于 200 个 http 请求...就像在浏览器中同时打开 200 个标签...难怪它会变慢
  • 没有代码 - 真的帮不上忙。这 200 个请求是同时进行的吗?即使他们不是,这听起来像是很多。对于初学者 - 启用 Firebug / 开发者控制台以查看网络活动
  • 触发 200 个 ajax 请求以进行单页访问的页面核心设计存在问题。另外,您使用的是同步还是异步传输?在给出进一步建议之前,您可以提供一些代码。
  • 浏览器标签的类比实际上并不适用。选项卡有很多开销(内存分配,可能是新进程/线程)。从互联网上拉下一段 JSON 与加载、解密和渲染一个完整的网页之间也有很多区别。然而,一个页面的 200 个 AJAX 请求仍然很多(不争论)——它甚至没有接近 200 个标签。

标签: javascript jquery ajax


【解决方案1】:

这里的问题不是 Ajax 请求,问题是每个请求都在更新 DOM。浏览器重绘是导致浏览器锁定的原因。

您需要找到一个不那么频繁地写入 DOM 的更好的解决方案。

【讨论】:

  • 你认为它的dom更新频率?即它们彼此有多近?我确实尝试研究一些排队/批处理方法,但找不到任何有用的东西。总体而言,90 秒内的 200 个请求相当于每秒 2 次更新。但在 90 秒内大约 20-30 次更新的情况下,平均每 3 秒更新一次 3 字节的 dom ......但问题仍然存在。
  • @Seer 这里有一些可能有用的信息:wilsonpage.co.uk/preventing-layout-thrashing 虽然我从未使用过他继续编写的“fastdom”库,但它用于更新 DOM 的技术越来越受欢迎。
猜你喜欢
  • 2015-12-17
  • 2015-08-12
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
  • 1970-01-01
  • 2010-10-08
相关资源
最近更新 更多