为什么多个同时的AJAX调用相同的ASP.NET MVC操作会导致浏览器阻塞?

几天前我问了这个问题:

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

我在同一个控制器动作下几乎同时激发了六个jQueryasynchronousajax请求。 每个请求需要10秒钟才能返回。

通过debugging和logging请求的行动方法,我注意到这些请求被序列化,永远不会并行运行。 即我在我的log4net日志中看到一个时间线,如下所示:

 2010-12-13 13:25:06,633 [11164]信息 - 得到:1156
 2010-12-13 13:25:16,634 [11164]信息 - 返回:1156
 2010-12-13 13:25:16,770 [7124]信息 - 得到:1426
 2010-12-13 13:25:26,772 [7124]信息 - 返回:1426
 2010-12-13 13:25:26,925 [11164]信息 - 得到:1912
 2010-12-13 13:25:36,926 [11164]信息 - 返回:1912年
 2010-12-13 13:25:37,096 [9812]信息 - 得到:1913
 2010-12-13 13:25:47,098 [9812]信息 - 回国:1913年
 2010-12-13 13:25:47,283 [7124]信息 - 得到:2002
 2010-12-13 13:25:57,285 [7124]信息 - 返回:2002
 2010-12-13 13:25:57,424 [11164]信息 - 得到:1308
 2010-12-13 13:26:07,425 [11164]信息 - 返回:1308

看看FireFox中的networking时间线,我看到这个:

替代文字

上面的日志示例和Firefoxnetworking时间线都是针对同一组请求的。

请求来自同一个页面的相同动作序列化? 我知道在同一会话中对Session对象的序列化访问,但是没有会话数据被触及。

我把客户端代码剥离到一个单一的请求(最长的一个),但这仍然阻止浏览器,即只有当Ajax请求完成时,浏览器响应任何链接点击。

我在这里观察到的(在Chrome的开发者工具中)是,当一个长时间运行的Ajax请求正在执行时点击一个链接,它会立即报告一个Failed to load resource错误,这表明浏览器已经杀死了(或正试图杀死并等待?)ajax请求:

替代文字

然而,浏览器仍然需要一个年龄redirect到新的页面。

ajax请求是否真的是asynchronous的,或者是这种手段,因为JavaScript实际上是单线程?

我的要求是否需要太长时间才能奏效?

Firefox和IE中也会出现这个问题。

我也改变脚本直接使用$.ajax ,并明确设置async: true

我在IIS7.5上运行这个,Windows 2008R2和Windows 7都是这样做的。

debugging和发布版本的行为也是一样的。

答案正在凝视着我。

ASP.NET会话状态概述 :

访问ASP.NET会话状态是每个会话独占的,这意味着如果两个不同的用户发出并发请求,则同时授予对每个单独会话的访问权限。 但是, 如果为同一会话创build了两个并发请求(通过使用相同的SessionID值),则第一个请求将获得对会话信息的独占访问权限。 第二个请求仅在第一个请求完成后执行。

令人讨厌的是,我几个星期前就已经略过了一段话,并没有真正考虑到这些大胆的句子的全部影响。 如果请求来自同一个会话,我已经读了,简单地说“访问会话状态是序列化的”,而不是“所有的请求,不pipe你是否触摸会话状态,都是序列化的”

幸运的是,在ASP.NET MVC3中有一个解决方法,可以创build无会话的控制器。 Scott Guthrie在这里谈到这些:

宣布ASP.NET MVC 3(Release Candidate 2)

我安装了MVC3 RC2并升级了项目。 使用[SessionState(SessionStateBehavior.Disabled)]装饰控制器解决了这个问题。

当然,通常我在几分钟前刚刚发现了Stack Overflow:

asynchronous控制器通过jQuery阻止ASP.NET MVC中的请求

我试图重现这一点,但无法。 这是我的testing:

 private static readonly Random _random = new Random(); public ActionResult Ajax() { var startTime = DateTime.Now; Thread.Sleep(_random.Next(5000, 10000)); return Json(new { startTime = startTime.ToString("HH:mm:ss fff"), endTime = DateTime.Now.ToString("HH:mm:ss fff") }, JsonRequestBehavior.AllowGet); } 

和电话:

 <script type="text/javascript" src="/scripts/jquery-1.4.1.js"></script> <script type="text/javascript"> $(function () { for (var i = 0; i < 6; i++) { $.getJSON('/home/ajax', function (result) { $('#result').append($('<div/>').html( result.startTime + ' | ' + result.endTime )); }); } }); </script> <div id="result"></div> 

结果是:

 13:37:00 603 | 13:37:05 969 13:37:00 603 | 13:37:06 640 13:37:00 571 | 13:37:07 591 13:37:00 603 | 13:37:08 730 13:37:00 603 | 13:37:10 025 13:37:00 603 | 13:37:10 166 

和FireBug控制台:

替代文字

正如你所看到的,AJAX动作是并行的。


更新:

看来,在我最初的testing中,使用$.getJSON()时,请求确实在FireFox 3.6.12和Chrome 8.0.552.215中排队。 它在IE8中工作正常。 我的testing是使用ASP.NET MVC 2项目,VS2010,Cassini Web服务器,Windows 7 x64位执行的。

现在,如果我用$.get()replace$.getJSON() ,它在所有浏览器下都可以正常工作。 这导致我相信这个$.getJSON()可能会导致请求排队。 也许有人更熟悉jQuery框架的内部,将能够更多地了解这个问题。


更新2:

尝试设置cache: false

 $.ajax({ url: '/home/ajax', cache: false, success: function (result) { $('#result').append($('<div/>').html( result.startTime + ' | ' + result.endTime )); } });