2010-01-19 14 views
5

Estoy escribiendo una aplicación web (compatible con Firefox solo) que utiliza un sondeo largo (a través de las capacidades ajax de jQuery) para enviar actualizaciones más o menos constantes del servidor al cliente. Me preocupan los efectos de dejarlo funcionando durante largos períodos de tiempo, por ejemplo, todo el día o toda la noche. El esqueleto de código básica es la siguiente:Mejorando el rendimiento de Ajax de sondeo largo

function processResults(xml) 
{ 
    // do stuff with the xml from the server 
} 

function fetch() 
{ 
    setTimeout(function() 
    { 
     $.ajax({ 
      type: 'GET', 
      url: 'foo/bar/baz', 
      dataType: 'xml', 
      success: function (xml) 
      { 
       processResults(xml); 
       fetch(); 
      }, 
      error: function (xhr, type, exception) 
      { 
       if (xhr.status === 0) 
       { 
       console.log('XMLHttpRequest cancelled'); 
       } 
       else 
       { 
        console.debug(xhr); 
        fetch(); 
       } 
      } 
     }); 
    }, 500); 
} 

(. El medio segundo "sueño" es para que el cliente no clavar el servidor si los cambios están llegando de nuevo al cliente de forma rápida - que por lo general son)

Después de dejarlo funcionando durante la noche, tiende a hacer que Firefox se arrastre. He estado pensando que esto podría ser causado parcialmente por una gran profundidad de la pila ya que básicamente he escrito una función infinitamente recursiva. Sin embargo, si uso Firebug y lanzo un punto de interrupción en fetch, parece que este no es el caso. La pila que Firebug me muestra tiene solo 4 o 5 cuadros de profundidad, incluso después de una hora.

Una de las soluciones que estoy considerando es cambiar mi función recursiva a una iterativa, pero no puedo entender cómo insertaría la demora entre las solicitudes Ajax sin girar. Miré el JS 1.7 "yield" keyword pero no puedo entenderlo, para ver si es lo que necesito aquí.

¿Es la mejor solución solo hacer una actualización en la página periódicamente, por ejemplo, una vez cada hora? ¿Hay un patrón de diseño de encuesta larga mejor/más delgado que no perjudique al navegador incluso después de funcionar durante 8 o 12 horas? ¿O debería omitir el largo sondeo y utilizar un patrón diferente de "actualización constante" ya que normalmente sé con qué frecuencia el servidor tendrá una respuesta para mí?

Respuesta

2

También es posible que sea FireBug. Usted está cargando la consola, lo que significa que probablemente tenga una pestaña de monitor de red abierta, etc., lo que significa que cada solicitud se almacena en la memoria.

Intenta inhabilitarlo, mira si eso ayuda.

+0

¡Eso me ayuda! – JulienFr

2

Sospecho que la memoria se está escapando de processResults().

He estado utilizando un código muy similar al suyo en una aplicación web de larga duración, que puede ejecutarse ininterrumpidamente durante semanas sin una actualización de página.

Su pila no debe ser profunda, porque fetch() regresa inmediatamente. No tienes un ciclo infinitamente recursivo.

Es posible que desee utilizar el Firefox Leak Monitor Add-on para ayudarlo a encontrar fugas de memoria.

+0

Pensé en eso como otra forma de "romper" la profundidad de la pila, pero no veo que tenga ningún efecto diferente del 'setTimeout' en mi código original. –

+0

Sí, sin embargo, su pila no debería profundizar, porque fetch() vuelve inmediatamente, por lo que las funciones de éxito y error salen de la pila bastante rápido. –

+0

Sospecho que tu memoria se está escapando de 'processResults()'. –

1

La profundidad de la pila de 4-5 es correcta. setTimeout y $.ajax son llamadas asincrónicas, que se devuelven inmediatamente. El navegador llama más tarde a la devolución de llamada con una pila de llamadas vacía. Como no puede implementar un sondeo largo de forma síncrona, debe usar este enfoque recursivo. No hay forma de hacerlo iterativo.

Sospecho que el motivo de esta ralentización es que su código tiene una pérdida de memoria. La fuga podría estar en $.ajax por jQuery (muy improbable) o en su llamada processResults.

1

No es buena idea llamar al fetch() desde el interior del método. La recursividad se usa mejor cuando se espera que en algún momento el método llegue a su fin y los resultados comiencen a enviarse a la persona que llama.El hecho es que cuando llama al método de forma recursiva, mantiene abierto el método de la persona que llama y utiliza la memoria. Si solo tienes 3-4 cuadros de profundidad, es porque jQuery o el navegador están de alguna manera "arreglando" lo que has hecho.

Las versiones recientes de jquery admiten el sondeo largo de forma predeterminada. De esta manera, puede estar seguro de que no depende de la inteligencia del navegador para manejar su llamada infinita recursiva. Cuando llame al método $.ajax(), puede usar el siguiente código para hacer una encuesta larga combinada con una espera segura de 500 milisegundos antes de una nueva llamada.

function myLongPoll(){ 
    setTimeout(function(){ 
     $.ajax({ 
      type:'POST', 
      dataType: 'JSON', 
      url: 'http://my.domain.com/action', 
      data: {}, 
      cache: false, 
      success:function(data){ 

       //do something with the result 

      }, 
      complete: myLongPoll, 
      async : false, 
      timeout: 5000 
     }); 
    //Doesn't matter how long it took the ajax call, 1 milisec or 
    //5 seconds (timeout), the next call will only happen after 2 seconds 
    }, 2000); 

De esta manera usted puede estar seguro de que la llamada $.ajax() se cierra antes de que comience la siguiente. Esto se puede probar agregando un simple console.log() al previo y otro después de su llamada $.ajax().

+0

Usar la devolución de llamada 'completa' de jQuery no es significativamente diferente de la implementación en mi pregunta. Esto no es Java: las personas que llaman nunca necesitan cerrar XHR u otros recursos explícitamente. –

Cuestiones relacionadas