2012-07-02 10 views
11

Tengo la siguiente consulta en jquery. Está leyendo la dirección de "publicación" de un par de suscripción/publicación de Nginx configurado utilizando el módulo de sondeo largo de Nginx.Chrome no maneja la consulta jquery ajax

function requestNextBroadcast() { 
     // never stops - every reply triggers next. 
     // and silent errors restart via long timeout. 
     getxhr = $.ajax({ 
      url: "/activity", 
      // dataType: 'json', 
      data: "id="+channel, 
      timeout: 46000, // must be longer than max heartbeat to only trigger after silent error. 
      error: function(jqXHR, textStatus, errorThrown) { 
       alert("Background failed "+textStatus); // should never happen 
       getxhr.abort(); 
       requestNextBroadcast(); // try again 
      }, 
      success: function(reply, textStatus, jqXHR) { 
       handleRequest(reply); // this is the normal result. 
       requestNextBroadcast(); 
      } 
     }); 
    } 

El código es parte de una sala de chat. Todos los mensajes enviados se responden con una respuesta nula (con 200/OK), pero los datos se publican. Este es el código para leer la dirección de suscripción a medida que los datos vuelven.

Usando un tiempo de espera, todas las personas en la sala de chat están enviando un mensaje simple cada 30 a 40 segundos, incluso si no escriben nada, por lo que hay una gran cantidad de datos para leer este código - al menos 2 y posiblemente más mensajes por 40 segundos.

El código es 100% sólido como una roca en EI y Firefox. Pero uno lee aproximadamente 5 errores en Chrome.

Cuando Chrome falla, tiene 46 segundos de tiempo de espera.

El registro muestra una solicitud de red de actividad pendiente en cualquier momento.

He estado rastreando este código durante 3 días, probando varias ideas. Y cada vez que IE y Firefox funcionan bien y Chrome falla.

Una sugerencia que he visto es hacer que la llamada sea sincrónica, pero eso es claramente imposible porque bloquearía la interfaz de usuario por mucho tiempo.

Editar - Tengo una solución parcial: El código es ahora esto

function requestNextBroadcast() { 
    // never stops - every reply triggers next. 
    // and silent errors restart via long timeout. 
    getxhr = jQuery.ajax({ 
     url: "/activity", 
     // dataType: 'json', 
     data: "id="+channel, 
     timeout: <?php echo $delay; ?>, 
     error: function(jqXHR, textStatus, errorThrown) { 
      window.status="GET error "+textStatus; 
      setTimeout(requestNextBroadcast,20); // try again 
     }, 
     success: function(reply, textStatus, jqXHR) { 
      handleRequest(reply); // this is the normal result. 
      setTimeout(requestNextBroadcast,20); 
     } 
    }); 
} 

El resultado es a veces la respuesta se retrasa hasta que el retardo $ (15.000) ocurre, entonces los mensajes en cola llegan demasiado rapidamente a seguir. No he podido hacer que deje caer mensajes (solo probado con netwrok optomisation off) con este nuevo arreglo.

Tengo muchas dudas de que haya demoras debido a problemas de red: todas las máquinas son máquinas virtuales dentro de mi única máquina real, y no hay otros usuarios de mi LAN local.

Editar 2 (viernes 2:30 BST) - Cambió el código para usar promesas - y el POST de acciones comenzó a mostrar los mismos síntomas, ¡pero el lado de recepción comenzó a funcionar bien! (???? !!! ???). Esta es la rutina POST: se trata de una secuencia de solicitudes para garantizar que solo sobresalga una por vez.

function issuePostNow() { 
    // reset heartbeat to dropout to send setTyping(false) in 30 to 40 seconds. 
    clearTimeout(dropoutat); 
    dropoutat = setTimeout(function() {sendTyping(false);}, 
          30000 + 10000*Math.random()); 
    // and do send 
    var url = "handlechat.php?"; 
    if (postQueue.length > 0) { 
     postData = postQueue[0]; 
     var postxhr = jQuery.ajax({ 
      type: 'POST', 
      url: url, 
      data: postData, 
      timeout: 5000 
     }) 
     postxhr.done(function(txt){ 
      postQueue.shift(); // remove this task 
      if ((txt != null) && (txt.length > 0)) { 
       alert("Error: unexpected post reply of: "+txt) 
      } 
      issuePostNow(); 
     }); 
     postxhr.fail(function(){ 
      alert(window.status="POST error "+postxhr.statusText); 
      issuePostNow(); 
     }); 
    } 
} 

Sobre una acción en la llamada a 8 handlechat.php habrá tiempo de espera y aparece la alerta. Una vez que se ha activado la alerta, llegan todos los mensajes en cola.

Y también noté que la llamada de handlechat estaba detenida antes de que escribiera el mensaje que otros verían. Me pregunto si podría ser un manejo extraño de los datos de sesión por php. Sé que pone en cola las llamadas para que los datos de la sesión no estén dañados, así que he tenido cuidado de usar diferentes navegadores o diferentes máquinas. Solo hay 2 subprocesos de php worker, pero php NO se usa en el manejo de/activity ni en el servicio de contenido estático.

También he pensado que podría ser una escasez de trabajadores nginx o procesadores php, así que los he planteado. Ahora es más difícil hacer que las cosas fallen, pero aún es posible. Supongo que la llamada/activity falla ahora una de cada 30 veces y no arroja ningún mensaje.

Y gracias muchachos por su contribución.


Resumen de los resultados.

1) Es un error en Chrome que ha estado en el código por un tiempo.
2) Con suerte, el error puede aparecer como una POST que no se envía y, cuando se agota, deja Chrome en tal estado que una POST repetida tendrá éxito.
3) La variable utilizada para almacenar el retorno de $ .ajax() puede ser local o global. Las nuevas (promesas) y las viejas llamadas de formato activan el error.
4) No he encontrado un trabajo para evitar el error.

Ian

+1

Si sospecha que es un problema de Chrome, podría ayudar a otros a saber qué versión está usando. jQuery versión también. – merv

+0

Chrome 20.0.1132.47 m jquery 1.7.2 Windows de O/S de 64 bits en el cliente y Ubuntu 11:04 en el servidor. – Ian

+0

He estado probando esto en Safari (5.1.7) y he encontrado que funciona. ASÍ QUE no es un problema de Webkit. También probado en la versión 20.0.1132.47 de Chrome para Linux y que tiene el problema. – Ian

Respuesta

2

trate de mover su función de sondeo en una Webworker para evitar que se congele en cromo. De lo contrario, podría intentar usar athe ajax .done() del objeto jquery. ese siempre funciona para mí en cromo.

+0

Gracias Michael. Webworker no es práctico - Debo soportar IE - y no es necesario porque nada de lo que hago lleva suficiente tiempo para notarlo. El problema no es que no se llame al éxito(), es que la lectura no termina INCLUSO CUANDO HAY INFORMACIÓN CONOCIDA QUE DEBE LEERSE.En resumen, el éxito puede ser invocado hasta 8 segundos después de que los datos estén disponibles. Sin embargo, revisaré done() y le haré saber. – Ian

+0

Lo que estaba pensando es que usted haga una comprobación de navegador, si es de color negro, active webworker que realiza una llamada síncrona. De esta forma, es posible que tengas una solución para Chrome, ya que solo Chrome proporciona problemas. Tengo que amar las diferencias del navegador. Espero que la solución .done funcione para ti. Eso es lo más fácil que implemento. – Tschallacka

0

Siento que getxhr debe tener el prefijo "var". ¿No desea una nueva solicitud de & completamente separada cada vez en lugar de sobreescribir la anterior en medio de un manejo de éxito/falla? Podría explicar por qué el comportamiento "mejora" cuando agrega setTimeout. También podría estar pasando algo;)

+0

getxhr es global, y no lo sobreescribo hasta que haya terminado con él, así que aunque podría hacerlo local, no veo la diferencia que podría causar. Me preguntaba si Chrome no estaba haciendo cola alguna operación de limpieza que se estaba realizando antes de volver a enviarla. – Ian

+0

Así que dices, pero tu código dice que lo estás escribiendo en exceso cada vez que se invoca requestNextBroadcast. Eso podría estar bien, después de todo, raramente uso el valor de retorno de $ .ajax – shovemedia

0

Los comentarios no serán formato de código, por lo que volver a colocar como una segunda respuesta:

Creo que Michael es Dibbets a algo con $ .ajax.done - empuja el patrón diferido procesando al próximo giro del ciclo de eventos, que creo que es el comportamiento que se necesita aquí. ver: http://www.bitstorm.org/weblog/2012-1/Deferred_and_promise_in_jQuery.html o http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/

me gustaría probar algo como:

function requestNextBroadcast() { 
    // never stops - every reply triggers next. 
    // and silent errors restart via long timeout. 

    getxhr = jQuery.ajax({ 
    url: "/activity", 
    // dataType: 'json', 
    data: "id="+channel, 
    timeout: <?php echo $delay; ?> 
    }); 

    getxhr.done(function(reply){ 
    handleRequest(reply); 
    }); 

    getxhr.fail(function(e){ 
    window.status="GET error " + e; 
    }); 

    getxhr.always(function(){ 
    requestNextBroadcast(); 
    }); 

Nota: Estoy teniendo un tiempo difícil encontrar documentación sobre los argumentos de devolución de llamada para Promise.done & Promise.fail :(

+0

¿Por qué no encadenas tus eventos? De esta forma, todos los eventos de devolución de llamada se inyectan sin demora. Ahora tiene el riesgo de que la recuperación de Ajax se complete antes de que se asigne un controlador completo y los procesos no coincidan. – Tschallacka

+0

* ¡altamente * improbable, pero buena captura! – shovemedia

+0

Lo sé ... pero después de haber visto crecer a Internet desde IE4 y netscape, nada me sorprende ya más ... He visto funcionar las cosas más imposibles (por ejemplo, el zoom: 1 cosa). Si no funciona de una manera, de otra forma podría hacerlo, y algunas veces tiene que hacer lo imposible para lograr algo ... Diferencias del navegador, Quién no los ama. – Tschallacka

0

Tal vez se puede evitar cambiando los ajustes del módulo de empuje (hay unos cuantos) - Podría, por favor publicar estos

Desde la parte superior de mi cabeza:

?
  • estableciéndolo en el intervalo de sondeo, sería un poco uglily resolverlo
  • la configuración de concurrencia podría tener algún efecto
  • almacenamiento de mensajes podría ser utilizado para evitar que los datos que faltan

También me gustaría usar algo como Charles para ver qué sucede exactamente en las capas de red/aplicación

4

Tuve un problema muy similar con Chrome. Estoy haciendo una llamada Ajax para obtener el tiempo de un servidor cada segundo. Obviamente, la llamada Ajax debe ser asincrónica porque congelará la interfaz en un tiempo de espera si no lo hace. Pero una vez que una de las llamadas Ajax es un fracaso, cada una subsecuente es también. Primero intenté establecer un tiempo de espera de 100 ms y funcionó bien en IE y FF, pero no en Chrome.Mi mejor solución estaba poniendo el tipo de puesto y que solucionó el error con cromo para mí:

setInterval(function(){ 
     $.ajax({ 
     url: 'getTime.php', 
     type: 'POST', 
     async: true, 
     timeout: 100, 
     success: function() { console.log("success"); }, 
     error: function() { console.log("error"); } 
     }); 
    }, 1000); 

Actualización: creo que el problema subyacente real aquí es la forma de almacenamiento en caché de Chrome. Parece que cuando falla una solicitud, esa falla se almacena en caché y, por lo tanto, las solicitudes posteriores nunca se realizan porque Chrome obtendrá la falla en caché antes de iniciar solicitudes posteriores. Esto se puede ver si va a las herramientas para desarrolladores de Chrome y va a la pestaña Red y examina cada solicitud que se realiza. Antes de una falla, las solicitudes de ajax a getTime.php se realizan cada segundo, pero después de una falla, las solicitudes posteriores nunca se inician. Por lo tanto, la siguiente solución que funcionó para mí:

setInterval(function(){ 
     $.ajax({ 
     url: 'getTime.php', 
     cache: false, 
     async: true, 
     timeout: 100, 
     success: function() { console.log("success"); }, 
     error: function() { console.log("error"); } 
     }); 
    }, 1000); 

El cambio aquí, es que estoy Desactivación de almacenamiento en caché para esta consulta Ajax, pero con el fin de hacerlo, la opción de tipo debe ser GET o HEAD, por eso me eliminado 'type: 'POST'' (GET es el valor predeterminado).

Cuestiones relacionadas