2010-12-13 20 views
68

Hace unos días hice esta pregunta:¿Por qué múltiples llamadas simultáneas de AJAX a la misma acción ASP.NET MVC causan el bloqueo del navegador?

Why does $.getJSON() block the browser?

yo fuego seis solicitudes jQuery ajax asíncrono al mismo controlador de la acción más o menos a la vez. Cada solicitud toma 10 segundos para regresar.

Mediante las solicitudes de depuración y registro al método de acción, veo que las solicitudes se serializan y nunca se ejecutan en paralelo. es decir, veo una línea de tiempo en mis registros log4net así:

 
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 

En cuanto a la línea de tiempo de la red en Firefox veo esto:

alt text

Tanto la muestra de registro de arriba y la línea de tiempo de red Firefox son para el mismo conjunto de solicitudes.

¿Están serializadas las solicitudes para la misma acción de la misma página? Conozco el acceso serializado al objeto Session en la misma sesión, pero no se tocan datos de la sesión.

Quité el código del lado del cliente a una sola solicitud (la más larga) pero esto todavía bloquea el navegador, es decir, solo cuando la solicitud AJAX se completa responde el navegador a cualquier enlace haciendo clic.

Lo que también observo aquí (en las herramientas de desarrollador de Chrome) es que al hacer clic en un enlace cuando se ejecuta una solicitud ajax de larga ejecución, informa un error Failed to load resource inmediatamente que sugiere que el navegador ha matado (o está intentando matar y en espera) la petición ajax:?

alt text

Sin embargo el navegador todavía toma una edad para redirigir a la nueva página.

¿Las solicitudes de ajax son realmente asíncronas o se trata de un truco porque javascript es en realidad un único subproceso?

¿Mis solicitudes simplemente demoran demasiado para que esto funcione?

El problema ocurre en Firefox y IE también.

También cambié la secuencia de comandos para usar $.ajax directamente y explícitamente establecer async: true.

Estoy ejecutando esto en IIS7.5, tanto el Windows 2008R2 y Windows 7 sabores hacen lo mismo.

Las compilaciones de depuración y liberación también se comportan igual.

+0

¿Se han probado esto en Firefox/IE. Tal vez es un problema de Chrome? –

+0

@aseem - es lo mismo en F/Fox e IE – Kev

+0

Tal vez su script cambie la configuración de sincronización en otro lugar. – ZippyV

Respuesta

85

La respuesta me estaba mirando a la cara.

ASP.NET Session State Overview:

acceso a estado de sesión ASP.NET es exclusivo por sesión, lo que significa que si dos usuarios distintos realizan solicitudes simultáneas, el acceso a cada sesión independiente se concede al mismo tiempo. Sin embargo, si se realizan dos solicitudes simultáneas para la misma sesión (utilizando el mismo valor de SessionID), la primera solicitud obtiene acceso exclusivo a la información de la sesión. La segunda solicitud se ejecuta solo después de que finaliza la primera solicitud.

Anormalmente había desnatado el párrafo esto hace un par de semanas sin realmente asimilar el impacto total de las oraciones en negrita. Había leído que simplemente como "el acceso al estado de la sesión está serializado" y no "todas las solicitudes, sin importar si se toca el estado de la sesión o no, se serializan" si las solicitudes provienen de la misma sesión.

Afortunadamente hay un problema en ASP.NET MVC3 y es posible crear controladores sin sesión.Scott Guthrie habla de estos aquí:

Announcing ASP.NET MVC 3 (Release Candidate 2)

he instalado RC2 MVC3 y actualizar el proyecto. Decorar el controlador en cuestión con [SessionState(SessionStateBehavior.Disabled)] resuelve el problema.

Y, por supuesto, por lo general me acaba de encontrar esto en desbordamiento de pila hace unos minutos:

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

+0

Gracias por esto. Estaba teniendo el mismo problema exacto. –

+0

¡Gracias por la ayuda con un error difícil! ¿Soy solo yo o este es el comportamiento predeterminado más estúpido? – theycallmemorty

+6

Tenga en cuenta que el uso de '[SessionState (SessionStateBehavior.Disabled)]' puede abrir una brecha de seguridad en su aplicación, por ejemplo, acceso a datos privados en múltiples solicitudes simultáneas, con esta opción no tiene forma de saber si un usuario está conectado, ni si una sesión está activa, etc. Si necesita acceder a la sesión, puede usar '[SessionState (SessionStateBehavior.ReadOnly)]', de modo que todavía tiene acceso a su sesión, aunque no puede editarla, pero aún así puede ayudar en muchos casos. –

7

Intenté reproducir esto pero no pude.Aquí está mi prueba:

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

Y la llamada:

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

Y los resultados:

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 

Y la consola de Firebug:

alt text

Un s puedes ver que la acción AJAX se golpea en paralelo.


ACTUALIZACIÓN:

Parece que en mis pruebas iniciales las solicitudes son de hecho cola en Firefox 3.6.12 y Chrome 8.0.552.215 cuando se utiliza $.getJSON(). Funciona bien en IE8. Mis pruebas se realizaron con un proyecto ASP.NET MVC 2, VS2010, servidor web Cassini, Windows 7 x64 bit.

Ahora si reemplazo $.getJSON() con $.get() funciona bien en todos los navegadores. Eso me lleva a creer que hay algo con este $.getJSON() que puede causar que las solicitudes hagan cola. Quizás alguien más familiarizado con los aspectos internos del marco jQuery pueda arrojar más luz sobre este asunto.


ACTUALIZACIÓN 2:

intente configurar cache: false:

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

gracias por experimentar .... este es un completo misterio sangriento :) – Kev

+1

Fuera de interés, ¿se probó con cassini o IIS? – Kev

+0

@Kev, sí, es un poco extraño. ¿Podría intentar reemplazar '$ .getJSON()' por '$ .get()'? Probé esto con Cassini. No tengo IIS instalado y no puedo verificar. –

Cuestiones relacionadas