Múltiples solicitudes de AJAX se retrasan entre sí

Tengo una solicitud de votación larga en mi página. La secuencia de comandos en el lado del servidor se establece en tiempo de espera después de 20 segundos.

Por lo tanto, cuando el sondeo largo está “inactivo” y el usuario presiona otro botón, el envío de esa nueva solicitud se retrasa hasta que se agote el tiempo de espera del script anterior.

No puedo ver nada malo con el código en el lado jQuery. ¿Por qué se retrasa el evento onclick?

function poll() { $.ajax({ url: "/xhr/poll/1", data: { user_id: app.user.id }, type: "POST", dataType: "JSON", success: pollComplete, error: function(response) { console.log(response); } }); } function pollComplete() { poll(); } function joinRoom(user_id) { $.ajax({ url: "/xhr/room/join", dataType: "JSON", type: "POST", data: { user_id: app.user.id, room_id: room.id } }); }  ############ PHP Controller on /xhr/poll $time = time(); while ((time() - $time) getNewStuff(); foreach ($updates->getResult() as $update) $response[] = $update->getResponse(); if (!empty($response)) return $response; else usleep(1 * 1000000); return 'no-updates'; } 

¿Podría ser el “sueño” el problema?

Captura de pantalla de XHR

Si utiliza sesiones en las funciones de manejo de AJAX, se encontrará con un problema en el que los datos de la sesión del disco están bloqueados por la primera solicitud, por lo que cada solicitud subsiguiente espera a que los datos de la sesión estén disponibles antes de continuar. En efecto, esto hace que las llamadas asíncronas se bloqueen entre sí, usted termina con respuestas lineales a las solicitudes en orden cronológico – sincrónicas. ( Aquí hay un artículo de referencia )

Una solución es usar session_write_close ( docs ) para cerrar la sesión tan pronto como ya no la necesite. Esto permite que otras solicitudes posteriores continúen porque los datos de la sesión se “desbloquearán”.

Esto, sin embargo, puede ser confuso también. Si llama a session_write_close justo antes de devolver una respuesta, entonces no va a hacerse ningún favor porque la sesión se habría desbloqueado tan pronto como se envió la respuesta. Por lo tanto, necesita ser llamado tan pronto como sea posible. Si está utilizando una architecture de estilo posterior a la solicitud de AJAX, esto no es tan malo, pero si tiene un marco más amplio y su controlador de solicitudes es solo una parte de él, tendrá que explorar una solución de nivel superior. al uso de sesión sin locking, por lo que sus subcomponentes no están cerrando una sesión que el marco espera que todavía esté abierto.

Una ruta es ir con sesión de base de datos. Esta solución tiene ventajas y desventajas que están más allá del scope de esta respuesta; consulte a Google para una discusión exhaustiva. Otra ruta es usar una función que abra una sesión, agregue una variable y luego la cierre. Corres el riesgo de las condiciones de carrera con esta solución, pero aquí hay un resumen:

 function get_session_var($key, $default=null) { if (strlen($key) < 1) return null; if (!isset($_SESSION) || !is_array($_SESSION)) { session_start(); session_write_close(); } if (array_key_exists($key, $_SESSION)) return $_SESSION[$key]; return $default; } function set_session_var($key, $value=null) { if (strlen($key) < 1) return false; if ($value === null && array_key_exists($key, $_SESSION)) { session_start(); unset($_SESSION[$key]); } elseif ($value != null) { session_start(); $_SESSION[$key] = $value; } else { return false; } session_write_close(); return true; } 

Esto suena consistente con la regla de 2 solicitudes: los navegadores solo permiten dos conexiones simultáneas al mismo host en un momento dado. Dicho esto, debería estar bien con una encuesta larga (recibir) y un canal de envío. ¿Está comenzando la encuesta larga después de la carga de la página usando $ (function () {…? ¿Está seguro de que la solicitud se está retrasando en el cliente y no en el navegador? ¿Qué está viendo en Firebug?

Una cosa que puede hacer, puede abortar la encuesta en ejecución y ejecutar su solicitud primero y luego volver a iniciar la encuesta.

 //make sure pollJqXhr.abort is not undefined var pollJqXhr={abort:$.noop}; function poll() { //assign actual jqXhr object pollJqXhr=jQuery.ajax({youroptions}); } function pollComplete() { poll(); } function joinRoom(user_id) { //pause polling pollJqXhr.abort(); jquery.ajax({ /*options here*/ success:function() { /*Your codes*/ //restart poll poll() } }); }