为什么多个同时的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 )); } });