web-dev-qa-db-fra.com

Pourquoi plusieurs appels simultanés AJAX à la même action ASP.NET MVC entraîneraient le blocage du navigateur?

Il y a quelques jours, j'ai posé cette question:

Pourquoi $ .getJSON () bloque-t-il le navigateur?

Je lance six requêtes ajQuync async jQuery à la même action du contrôleur à peu près tout à la fois. Chaque demande prend 10 secondes pour revenir.

Grâce au débogage et à la journalisation des demandes à la méthode d'action, je remarque que les demandes sont sérialisées et ne s'exécutent jamais en parallèle. c'est-à-dire que je vois une chronologie dans mes journaux log4net comme ceci:

 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 - Obtenu: 1912 
 2010-12-13 13: 25: 36,926 [11164] INFO - Retour: 1912 
 2010-12-13 13: 25: 37 096 [9812] INFO - Obtenu: 1913 
 13/12/2010 13:25: 47 098 [9812] INFO - Retour: 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 - Obtenu: 1308 
 13/12/2010 13: 26: 07,425 [11164] INFO - Retour: 1308 

En regardant la chronologie du réseau dans FireFox, je vois ceci:

alt text

L'exemple de journal ci-dessus et la chronologie du réseau Firefox concernent le même ensemble de demandes.

Les demandes à la même action de la même page sont-elles sérialisées? Je suis conscient de l'accès sérialisé à l'objet Session dans la même session , mais aucune donnée de session n'est touchée.

J'ai supprimé le code côté client en une seule demande (la plus longue), mais cela bloque toujours le navigateur, c'est-à-dire uniquement lorsque la demande ajax est terminée, le navigateur répond à tout clic sur un lien.

Ce que j'observe également ici (dans les outils de développement de Chrome), c'est qu'en cliquant sur un lien lorsqu'une longue demande ajax s'exécute, il signale un Failed to load resource erreur immédiatement qui suggère que le navigateur a tué (ou tente de tuer et attend?) la demande ajax:

alt text

Cependant, le navigateur prend encore un certain temps pour rediriger vers la nouvelle page.

Les demandes ajax sont-elles vraiment asynchrones ou est-ce un tour de passe-passe parce que javascript est en fait un seul thread?

Mes demandes prennent-elles trop de temps pour que cela fonctionne?

Le problème se produit dans Firefox et IE également.

J'ai également changé le script pour utiliser $.ajax définir directement et explicitement async: true.

J'exécute cela sur IIS7.5, les versions Windows 2008R2 et Windows 7 font la même chose.

Les versions de débogage et de publication se comportent également de la même manière.

72
Kev

La réponse me fixait en face.

Présentation de l'état de la session ASP.NET :

L'accès à l'état de session ASP.NET est exclusif par session, ce qui signifie que si deux utilisateurs différents effectuent des demandes simultanées, l'accès à chaque session distincte est accordé simultanément. Cependant, si deux demandes simultanées sont effectuées pour la même session (en utilisant la même valeur SessionID), la première demande obtient un accès exclusif aux informations de session. La deuxième demande s'exécute uniquement une fois la première demande terminée.

De façon ennuyeuse, j'avais survolé ce paragraphe il y a quelques semaines, sans vraiment saisir le plein impact des phrases en gras. J'avais lu cela simplement comme "l'accès à l'état de session est sérialisé" et non "toutes les requêtes, que vous touchiez l'état de session ou non, sont sérialisées" = si les demandes provenaient de la même session.

Heureusement, il existe un travail autour d'ASP.NET MVC3 et il est possible de créer des contrôleurs sans session. Scott Guthrie en parle ici:

Annonce d'ASP.NET MVC 3 (Release Candidate 2)

J'ai installé MVC3 RC2 et mis à niveau le projet. Décorer le contrôleur en question avec [SessionState(SessionStateBehavior.Disabled)] résout le problème.

Et bien sûr, généralement, je viens de trouver cela dans Stack Overflow il y a quelques minutes:

Le contrôleur asynchrone bloque les demandes dans ASP.NET MVC via jQuery

89
Kev

J'essayais de reproduire cela mais je n'ai pas réussi. Voici mon 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);
}

Et l'appel:

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

Et les résultats:

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

Et la console FireBug:

alt text

Comme vous pouvez le voir, l'action AJAX est lancée en parallèle.


MISE À JOUR:

Il semble que dans mes tests initiaux, les demandes soient en effet mises en file d'attente dans FireFox 3.6.12 et Chrome 8.0.552.215 lors de l'utilisation de $.getJSON() . Cela fonctionne très bien dans IE 8. Mes tests ont été effectués avec un projet ASP.NET MVC 2, VS2010, serveur Web Cassini, Windows 7 x64 bits.

Maintenant, si je remplace $.getJSON() par $.get() cela fonctionne très bien sous tous les navigateurs. Cela m'amène à croire qu'il y a quelque chose avec cette $.getJSON() qui pourrait provoquer la mise en file d'attente des requêtes. Peut-être que quelqu'un plus familier avec les éléments internes du cadre jQuery serait en mesure de faire la lumière sur cette question.


MISE À JOUR 2:

Essayez de définir cache: false:

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