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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4428413/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 12:22:56  来源:igfitidea点击:

Why would multiple simultaneous AJAX calls to the same ASP.NET MVC action cause the browser to block?

javascriptjqueryasp.net-mvcajaxasp.net-mvc-2

提问by Kev

A few days back I asked this question:

前几天我问了这个问题:

Why does $.getJSON() block the browser?

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

I fire six jQuery async ajax requests at the same controller action pretty much all at once. Each request takes 10 seconds to return.

我几乎同时在同一个控制器操作上发出六个 jQuery 异步 ajax 请求。每个请求需要 10 秒才能返回。

Through debugging and logging requests to the action method I notice that the requests are serialised and never run in parallel. i.e. I see a timeline in my log4net logs like this:

通过调试和记录对 action 方法的请求,我注意到请求是序列化的,永远不会并行运行。即我在我的 log4net 日志中看到一个时间线,如下所示:

2010-12-13 13:25:06,633 [11164] INFO   - Got:1156
2010-12-13 13:25:16,634 [11164] INFO   - Returning:1156
2010-12-13 13:25:16,770 [7124] INFO   - Got:1426
2010-12-13 13:25:26,772 [7124] INFO   - Returning:1426
2010-12-13 13:25:26,925 [11164] INFO   - Got:1912
2010-12-13 13:25:36,926 [11164] INFO   - Returning:1912
2010-12-13 13:25:37,096 [9812] INFO   - Got:1913
2010-12-13 13:25:47,098 [9812] INFO   - Returning:1913
2010-12-13 13:25:47,283 [7124] INFO   - Got:2002
2010-12-13 13:25:57,285 [7124] INFO   - Returning:2002
2010-12-13 13:25:57,424 [11164] INFO   - Got:1308
2010-12-13 13:26:07,425 [11164] INFO   - Returning:1308

Looking at the network timeline in FireFox I see this:

查看 FireFox 中的网络时间线,我看到:

alt text

替代文字

Both the log sample above and the Firefox network timeline are for the same set of requests.

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

Are requests to the same action from the same page serialised?I'm aware of serialised access to the Sessionobject in the same session, but no session data is being touched.

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

I stripped the client side code down to a single request (the longest running one) but this still blocks the browser, i.e. only when the ajax request completes does the browser respond to any link clicking.

我将客户端代码剥离为单个请求(运行时间最长的请求),但这仍然会阻止浏览器,即只有当 ajax 请求完成时,浏览器才会响应任何链接点击。

What I also observe here (in Chrome's developer tools) is that upon clicking on a link when a long running ajax request is executing it reports a Failed to load resourceerror immediately which suggests that the browser has killed (or is attempting to kill and waiting?) the ajax request:

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

alt text

替代文字

However the browser still takes an age to redirect to the new page.

然而,浏览器仍然需要一段时间才能重定向到新页面。

Are ajax requests really asynchronous or is this sleight of hand because javascript is actually single threaded?

ajax 请求是否真的是异步的,还是因为 javascript 实际上是单线程的,所以这是一种花招?

Are my requests just taking too long for this to work?

我的请求是否需要太长时间才能起作用?

The problem occurs in Firefox and IE as well.

Firefox 和 IE 中也会出现此问题。

I also changed the script to use $.ajaxdirectly and explicitly set async: true.

我还更改了脚本以$.ajax直接和显式地使用set async: true

I'm running this on IIS7.5, both the Windows 2008R2 and Windows 7 flavours do the same thing.

我在 IIS7.5 上运行它,Windows 2008R2 和 Windows 7 版本都做同样的事情。

Debug and release builds also behave the same.

调试和发布版本的行为也相同。

回答by Kev

The answer was staring me in the face.

答案是盯着我的脸。

ASP.NET Session State Overview:

Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, if two concurrent requests are made for the same session (by using the same SessionID value), the first request gets exclusive access to the session information. The second request executes only after the first request is finished.

ASP.NET 会话状态概述

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

Annoyingly I'd skimmed paragraph this a couple of weeks ago not really taking in the full impact of the bold sentences. I had read that simply as "access to session state is serialised"and not "all requests, no matter whether you touch session state or not, are serialised"if the requests came from the same session.

令人讨厌的是,几周前我略读了这一段,并没有真正考虑到大胆句子的全部影响。如果请求来自同一个会话,我已经简单地将其理解为“对会话状态的访问被序列化”,而不是“所有请求,无论您是否触摸会话状态,都被序列化”

Fortunately there is a work around in ASP.NET MVC3 and its possible to create session-less controllers. Scott Guthrie talks about these here:

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

Announcing ASP.NET MVC 3 (Release Candidate 2)

宣布 ASP.NET MVC 3(发布候选 2)

I installed MVC3 RC2 and upgraded the project. Decorating the controller in question with [SessionState(SessionStateBehavior.Disabled)]solves the problem.

我安装了 MVC3 RC2 并升级了项目。装饰有问题的控制器可以[SessionState(SessionStateBehavior.Disabled)]解决问题。

And of course typically I just found this in Stack Overflow a few minutes ago:

当然,通常我几分钟前才在 Stack Overflow 中找到了这个:

Asynchronous Controller is blocking requests in ASP.NET MVC through jQuery

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

回答by Darin Dimitrov

I was trying to reproduce this but was unable. Here's my test:

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

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);
}

And the call:

和电话:

<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>

And the results:

结果:

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

And the FireBug console:

和 FireBug 控制台:

alt text

替代文字

As you can see the AJAX action is hit in parallel.

如您所见,AJAX 操作是并行执行的。



UPDATE:

更新:

It seems that in my initial tests the requests are indeed queued in FireFox 3.6.12 and Chrome 8.0.552.215 when using $.getJSON(). It works fine in IE8. My tests were performed with a ASP.NET MVC 2 project, VS2010, Cassini web server, Windows 7 x64 bit.

似乎在我的初始测试中,使用$.getJSON(). 它在 IE8 中运行良好。我的测试是使用 ASP.NET MVC 2 项目、VS2010、Cassini Web 服务器、Windows 7 x64 位执行的。

Now if I replace $.getJSON()with $.get()it works fine under all browsers. That leads me to believe that there is something with this $.getJSON()which might cause the requests to queue. Maybe someone more familiar with the internals of the jQuery framework would be able to shed more light on this matter.

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



UPDATE 2:

更新 2:

Try setting cache: false:

尝试设置cache: false

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