问题 为什么$ .getJSON()会阻止浏览器?


我有一个页面,列出了我们为客户监控的硬件设备。显示的每一行还显示设备的状态,即它是否正在运行,暂停,启动等。

为了改善页面加载时间,我列出了设备,但在呈现页面之前不会查询它们的状态。这是因为某些查询(例如通过SNMP或其他API)可能需要5-10秒才能响应。因此,对于十个设备的列表,用户可能需要一分钟才能看到空白页面。所以我做了以下事情 -

在设备列表页面上,我有以下脚本:

$(document).ready(function () {

  var devices = $('div[name="runStatus"]');
  devices.each(function () {

    // Get device ID (I embed this using the HTML5 data-* attributes/annotations)
    var deviceId = $(this).attr("data-deviceid");
    var url = "/devmanager/status/" + deviceId;

    $.getJSON(url, function (response) {
      // Not actually important to the question...set text status, colours etc
      $('div[data-deviceid="' + deviceId + '"]').text(response);
      //...
    });
  });
});

我发现如果我允许这个脚本运行,页面上的所有链接都会无法响应。

我猜这是因为我有很多几乎并行的异步请求阻塞,直到他们从服务器得到响应,并且某种程度上“UI线程”被这个阻止?

但是我认为这不应该发生在AJAX上。

我发现在IE8,Chrome 8.0和Firefox 3.6中会发生这种“阻塞”行为。 Chrome实际上显示了箭头光标+旋转 - 马桶 - 死亡(我正在使用Windows 7),就像页面没有完全呈现一样。

我怎样才能解决这个问题?


7355
2017-12-05 16:48


起源

设备集合中有多少项?您可能只能同时执行2或3个并发Ajax请求,其余的将排队,可能会减慢加载页面的其余部分(下载图像等)。 - Douglas
$('div [data-deviceid =“'+ deviceId +'”]')。text(response);看起来像一个相当昂贵的选择器至少在更大的页面上。如果删除回调中的所有代码,然后页面运行得很快,那就是原因。值得一试! - Mikael Eliasson
@douglas,@ mikael - 列表中有6个项目。设置这些值(在for循环中)发生在眨眼间。 - Kev
如果您说列表中包含50多个项目,那么我不会对这种行为感到惊讶......但是6 ..令人惊讶的是,六个同步异步请求足以堵塞浏览器/操作系统。您可以发布相关页面的链接吗?我想看看它如何在Safari / Mac上运行,并通过可靠的旧Web代理查看。 - Lee
@Lee - 我会点击你可以测试的网站。生产资料在密码保护的门户网站后面运行,因此您无法轻松获得它。 - Kev


答案:


我想你在处理多个请求时遇到了浏览器限制。

您是否尝试过使用Fiddler并查看时间轴以查看阻塞内容?

这个问题可能会有所帮助:

流行的浏览器允许多少并发AJAX(XmlHttpRequest)请求?


5
2017-12-05 19:07



仅供参考 - 请参阅我的回答。 - Kev
有趣。感谢更新。 - ScottE


事实证明这不是客户端的问题:

多次调用同一个ASP.NET MVC操作会导致浏览器阻塞吗?

多次调用同一个ASP.NET MVC操作会导致浏览器阻塞吗? - 回答

这是由ASP.NET的“按设计”功能引起的,其中在同一会话中发出的多个请求被序列化。


5
2017-12-14 00:44





听起来像getJSON使用异步:false作为xhr的选项。尽管如此,jquery会将其用作默认值,这让我很高兴,因为由于你所描述的原因,这几乎总是一个坏主意。

目前没有时间更多地研究它,但这是我要采取的第一条道路。


0
2017-12-05 17:08



根据文档,$ .getJSON()是一个简写的$ .ajax()调用,它设置async:true。 - Kev


我从来没有遇到过$ .getJSON()的问题。据我所知,它是异步的。 可能发生的是一个javascript错误,因为你正在尝试:

$('div[data-deviceid="' + deviceId + '"]').text(response);

我猜这里有一个错误,因为 响应 是一个javascript对象或数组,而不是一个字符串。 你应该做的是 文本(response.desiredProperty) 要么 文本(响应[指数]) 根据对象的类型 响应 是。

由于javascript错误有时会使我们的浏览器出现意外行为,因此可能(仅限于)我的问题。


0
2017-12-05 17:16



这不是一个javascript错误。响应也是一串......信任我。我在Firebug / Chrome开发工具中检查了所有这些。问题肯定与异步调用有关。你是对的,$ .getJSON是一个用于调用$ .ajax()的异步简写方法。 - Kev
另外......当我注释掉这一行时 $('div[data-deviceid="' + deviceId + '"]').text(response); 问题依然存在。 - Kev
有趣......我只是觉得这可能是问题,但事实证明我完全错了。这个问题引出了ScottE的答案,这是非常有趣的,并且可能在很多不同的情况下发生。我将再次检查这一点,看看你做了什么来解决/解决这个问题。 - Marcelo Zabani