Почему несколько одновременных вызовов AJAX для одного и того же действия ASP.NET MVC приводят к блокировке браузера? - PullRequest
72 голосов
/ 13 декабря 2010

Несколько дней назад я задал этот вопрос:

Почему $ .getJSON () блокирует браузер?

Я запускаю шесть 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   - Got:1308
2010-12-13 13:26:07,425 [11164] INFO   - Returning:1308

Глядя на сетевую шкалу в FireFox, я вижу это:

alt text

Пример журнала, приведенный выше, и временная шкала сети Firefox относятся к одному и тому же набору запросов.

Сериализуются ли запросы на одно и то же действие с одной и той же страницы? Мне известно о сериализованном доступе к объекту Session в том же сеансе, но данные сеанса не затрагиваются.

Я сократил код на стороне клиента до одного запроса (самый продолжительный), но он по-прежнему блокирует браузер, т. Е. Только когда запрос ajax завершается, браузер реагирует на нажатие любой ссылки.

Я также наблюдаю здесь (в инструментах разработчика Chrome), что при нажатии на ссылку, когда выполняется долго выполняющийся запрос ajax, она немедленно сообщает об ошибке Failed to load resource, которая указывает на то, что браузер убил (или пытается убить) и ждете?) запрос ajax:

alt text

Однако браузеру все еще требуется время, чтобы перенаправить на новую страницу.

Являются ли запросы ajax действительно асинхронными или это ловкость рук, потому что на самом деле JavaScript является однопоточным?

Мои запросы просто слишком долго работают?

Проблема возникает также в Firefox и IE.

Я также изменил скрипт, чтобы использовать $.ajax напрямую и явно установить async: true.

Я запускаю это на IIS7.5, оба варианта Windows 2008R2 и Windows 7 делают одно и то же.

Сборки отладки и выпуска также ведут себя одинаково.

Ответы [ 2 ]

89 голосов
/ 14 декабря 2010

Ответ смотрел мне в лицо.

Обзор состояния сеанса ASP.NET :

Доступ к состоянию сеанса ASP.NET является эксклюзивным для каждого сеанса, что означает, что если два разных пользователя делают параллельные запросы, доступ к каждому отдельному сеансу предоставляется одновременно. Однако , если два одновременных запроса сделаны для одного и того же сеанса (с использованием одного и того же значения SessionID), первый запрос получает эксклюзивный доступ к информации сеанса. Второй запрос выполняется только после того, как первый запрос завершен.

Досадно, что я просмотрел этот параграф пару недель назад, не особо учитывая весь смысл смелых предложений. Я читал это просто: "сериализован доступ к состоянию сеанса" , а не "все запросы, независимо от того, касаетесь ли вы состояния сеанса или нет, сериализуются" , если запросы поступили из тот же сеанс.

К счастью, в ASP.NET MVC3 есть обходной путь и возможно создание контроллеров без сессий. Скотт Гатри говорит об этом здесь:

Объявление ASP.NET MVC 3 (Кандидат на выпуск 2)

Я установил MVC3 RC2 и обновил проект. Декорирование рассматриваемого контроллера с помощью [SessionState(SessionStateBehavior.Disabled)] решает проблему.

И, конечно, обычно я только что нашел это в переполнении стека несколько минут назад:

Асинхронный контроллер блокирует запросы в ASP.NET MVC через jQuery

8 голосов
/ 13 декабря 2010

Я пытался воспроизвести это, но не смог.Вот мой тест:

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, Windows 7 x64 bit.

Теперь, если я заменим $.getJSON() на $.get(), он прекрасно работает во всех браузерах.Это наводит меня на мысль, что с этим $.getJSON() есть что-то, что может вызвать запросы в очередь.Может быть, кто-то, более знакомый с внутренностями фреймворка jQuery, сможет пролить больше света на этот вопрос.


ОБНОВЛЕНИЕ 2:

Попробуйте установить cache: false:

$.ajax({
    url: '/home/ajax', 
    cache: false,
    success: function (result) {
        $('#result').append($('<div/>').html(
            result.startTime + ' | ' + result.endTime
        ));
    }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...