2010-02-03 8 views
5

Tengo una llamada Ajax que actualmente necesita ser sincrónica. Sin embargo, mientras se ejecuta esta llamada Ajax, la interfaz del navegador se congela, hasta que la llamada regrese. En casos de tiempo de espera, esto puede congelar el navegador para un significant period of time.¿Es posible obtener una ventana del navegador para actualizar mientras está en un bucle de Javascript?

¿Hay alguna manera de obtener el navegador (cualquier navegador) para actualizar la interfaz de usuario, pero no ejecutar ningún Javascript? Idealmente, sería algún comando como window.update(), que permitiría actualizar la cadena de usuario.

Si esto no sería posible, entonces yo podría sustituir a la llamada AJAX sincrónica con algo como:

obj = do_async_ajax_call(); 
while (!obj.hasReturned()) { 
    window.update(); 
} 
// synchronous call can resume 

La razón por la que no puedo usar setTimeout, o reanudar una función en la devolución de llamada, es que el flujo de ejecución no se puede interrumpir: (hay demasiadas variables de estado que todos dependen unos de otros, y el flujo long_function() otra manera tendrían que ser reanudado de alguna manera):

function long_function() { 
    // lots of code, reads/writes variable 'a', 'b', ... 
    if (sync_call_is_true()) { 
    // lots of code, reads/writes variable 'a', 'b', ... 
    } else { 
    // lots of code, reads/writes variable 'a', 'b', ... 
    } 
    // lots of code, reads/writes variable 'a', 'b', ... 
    return calculated_value; 
} 
+2

¿Por qué la llamada debe ser sincrónica? –

+1

¿Puedes publicar el código de la llamada completa? Esto probablemente puede simplificarse y usar las funciones XHR para respaldar lo que necesita (a menos que jQuery sea una opción, y luego incluso más limpio). Si ninguno es una opción, le pido que cambie el nombre de la función a 'do_sync_jax_call();' –

Respuesta

3

Es necesario sustituir su petición síncrona con una solicitud asincrónica y usar una devolución de llamada. Un ejemplo muy simplificado sería:

obj = do_async_ajax_call(function (data, success) 
{ 
    if (success) 
    { 
     // continue... 
    } 
}); 

function do_async_ajax_call(callback) 
{ 
    var xhr = new XMLHttpRequest(); 
    xhr.open("GET", "http://mysite.com", true); 
    xhr.onreadystatechange = function() 
    { 
     if (xhr.readyState == 4 && xhr.status == 200) 
      callback(xhr.responseXML, true); 
     else if (xhr.readyState == 4) 
      callback(null, false); 
    } 
    xhr.send(); 
} 

De esta manera estás pasando una función anónima como parámetro a la función que solicita ajax. Cuando se completa el ajax, se llama a la función que se pasó con la responseXML que se le pasó. Mientras tanto, el navegador ha sido libre de hacer lo habitual hasta que finalice la llamada. A partir de aquí, el resto de tu código continúa.

+0

Esto normalmente sería suficiente, pero no puedo dividir el flujo de operación (como se actualiza en la pregunta). Estoy probando otro enfoque ahora ... – jevon

+0

Es * siempre * posible dividirlo; esta es la transformación de CPS (busque "estilo de continuación de paso"; el parámetro de continuación es su devolución de llamada). Las variables de estado locales simplemente se cierran en la función de devolución de llamada. Los bucles se convierten en llamadas recursivas. No es tan difícil ni oscuro una vez que lo dominas. –

+0

Acepto que siempre es posible, pero en este caso no fue la mejor solución (¡hubo demasiadas variables de estado!) :) Al final, utilicé el resultado de devoluciones de llamada previas (o sondeo regular del servidor) para actualizar el cliente - lado con un valor en caché de la llamada síncrona cuando sea necesario, por lo que no necesita llamar a Ajax en absoluto. – jevon

0

tomar el resto de la llamada y la puso en la devolución de llamada que se llama cuando el resultado vuelve. Dudo seriamente que esto sea completamente imposible para ti. Cualquier lógica que necesita para poner en la llamada puede ser duplicado en la devolución de llamada

0

ajax búsqueda asíncrona continuación setTimeout y hacer el trabajo de procesamiento en trozos (provocada por la devolución de llamada)

0

JavaScript es de subproceso único. Entonces, por definición, no puede actualizar la IU mientras se encuentra en un ciclo de marea. Sin embargo, a partir de Firefox 3.5, existe un soporte adicional para JavaScripts de subprocesos múltiples llamados trabajadores web. Los trabajadores web no pueden afectar la IU de la página, pero tampoco bloquearán las actualizaciones de la IU. Nosotros, los trabajadores, también somos compatibles con Chrome y Safari.
El problema es que, incluso si mueve su llamada AJAX al hilo de fondo y espera a que finalice la ejecución, los usuarios podrán presionar los botones y cambiar los valores en su UI (y por lo que yo sé, eso es lo que tratando de evitar). Lo único que puedo sugerir para evitar que los usuarios causen cualquier cambio es un spinner que bloqueará toda la interfaz de usuario y no permitirá ninguna interacción con la página hasta que regrese la llamada web.

+0

No me importa si los usuarios interactúan con la página (y la interacción se pone en cola); pero actualmente, mientras se ejecuta una llamada síncrona Ajax en Firefox, todo el navegador se congela. Esto es lo que quiero prevenir. – jevon

Cuestiones relacionadas