web-dev-qa-db-ja.com

同じASP.NET MVCアクションへの複数の同時AJAX呼び出しにより、ブラウザーがブロックされるのはなぜですか?

数日前、私はこの質問をしました:

なぜ$ .getJSON()がブラウザをブロックするのですか?

同じコントローラーアクションで6つのjQuery非同期ajaxリクエストをほぼ同時に実行します。各リクエストが返されるまでに10秒かかります。

アクションメソッドへのリクエストのデバッグとログ記録により、リクエストがシリアル化され、並行して実行されることはありません。つまり、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-取得済み:1308 
 2010-12-13 13:26:07,425 [11164] INFO-Returning:1308 

FireFoxのネットワークタイムラインを見ると、次のことがわかります。

alt text

上記のログサンプルとFirefoxネットワークタイムラインの両方は、同じリクエストセットに対するものです。

同じページからの同じアクションへのリクエストはシリアル化されていますか?同じセッション内のSessionオブジェクトへのシリアル化されたアクセスを知っています、ただしセッションデータは変更されていません。

クライアント側のコードを1つのリクエスト(最も長く実行されているもの)に落としましたが、これはブラウザをブロックします。つまり、ajaxリクエストが完了すると、ブラウザはリンクのクリックに応答します。

ここで私が観察しているのは(Chromeの開発者ツールで)、長時間実行されているajaxリクエストが実行されているときにリンクをクリックすると、ブラウザーが強制終了(または強制終了しようとしていることを示すFailed to load resourceエラーをすぐに報告することです待っていますか?)ajaxリクエスト:

alt text

ただし、ブラウザは新しいページにリダイレクトするにはまだ時間がかかります。

Ajaxリクエストは本当に非同期ですか、それともJavaScriptは実際にはシングルスレッドであるため、この手軽さですか?

私のリクエストはこれが機能するのに時間がかかりすぎていますか?

この問題はFirefoxで発生し、IEも同様です。

また、$.ajaxを直接使用し、async: trueを明示的に設定するようにスクリプトを変更しました。

これをIIS7.5で実行していますが、Windows 2008R2とWindows 7の両方のフレーバーは同じことを行います。

デバッグビルドとリリースビルドも同じように動作します。

72
Kev

答えは私を正面から見つめていた。

ASP.NETセッション状態の概要

ASP.NETセッション状態へのアクセスはセッションごとに排他的です。つまり、2人の異なるユーザーが同時リクエストを行うと、各セッションへのアクセスが同時に許可されます。ただし、同じセッションに対して2つの同時要求が(同じSessionID値を使用して)行われた場合、最初の要求はセッション情報への排他的アクセスを取得します。 2番目のリクエストは、最初のリクエストが終了した後にのみ実行されます。

わずらわしいことに、私は数週間前にこの段落をざっと読み、大胆な文章の影響を完全には取り入れていませんでした。私は、「セッション状態へのアクセスがシリアル化される」ではなく」と読みました。すべてのリクエストは、セッション状態に触れるかどうかに関係なく、リクエストが同じセッションから送信された場合は、「シリアル化」

幸いなことに、ASP.NET MVC3には回避策があり、セッションレスコントローラーを作成できます。スコット・ガスリーはここでこれらについて話します:

ASP.NET MVC 3(リリース候補2)の発表

MVC3 RC2をインストールし、プロジェクトをアップグレードしました。問題のコントローラーを[SessionState(SessionStateBehavior.Disabled)]で装飾すると問題が解決します。

もちろん、通常は数分前にStack Overflowでこれを見つけました。

非同期コントローラーはjQueryを介してASP.NET MVCの要求をブロックしています

89
Kev

これを再現しようとしていましたが、できませんでした。私のテストは次のとおりです。

_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コンソール:

alt text

ご覧のとおり、AJAXアクションは並行してヒットします。


更新:

私の最初のテストでは、リクエストは実際にFireFox 3.6.12とChrome 8.0.552.215で $.getJSON() を使用するときにキューに入れられます。 IE8では問題ありませんが、テストはASP.NET MVC 2プロジェクト、VS2010、Cassini Webサーバー、Windows 7 x64ビットで実行されました。

$.getJSON()$.get() に置き換えると、すべてのブラウザーで問題なく動作します。そのため、この$.getJSON()にはリクエストがキューイングされる可能性があるものがあると信じられます。 jQueryフレームワークの内部に精通している誰かが、この問題をさらに明らかにできるかもしれません。


更新2:

_cache: false_を設定してみてください:

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