2011-09-26 12 views
6

Tengo una clase, ChatRoom, que solo se puede procesar después de recibir una solicitud HTTP de larga ejecución (podría tomar 1 segundo o 30 segundos). Entonces necesito retrasar el renderizado hasta que ChatRoom.json no sea nulo.Retraso asincrónico de JS hasta que se cumpla una condición

En el siguiente código, estoy usando Closure Library's goog.async.ConditionalDelay. Funciona, pero ¿hay una mejor manera (tal vez sin necesidad de Closure Library) para hacer esto?

ChatRoom.prototype.json = null; // received after a long-running HTTP request. 

ChatRoom.prototype.render = function() { 
    var thisChatRoom = this; 

    function onReady() { 
     console.log("Received JSON", thisChatRoom.json); 
     // Do rendering... 
    } 

    function onFailure() { 
     alert('Sorry, an error occurred. The chat room couldn\'t open'); 
    } 

    function isReady() { 
     if (thisChatRoom.json != null) { 
      return true; 
     } 
     console.log("Waiting for chat room JSON..."); 
     return false; 
    } 

    // If there is a JSON request in progress, wait until it completes. 
    if (isReady()) { 
     onReady(); 
    } else { 
     var delay = new goog.async.ConditionalDelay(isReady); 
     delay.onSuccess = onReady; 
     delay.onFailure = onFailure; 
     delay.start(500, 5000); 
    } 
} 

Nota que "si bien (JSON == null) {}" no es posible, porque eso sería síncrona (bloqueando todos los demás ejecución JS).

+2

¿Por qué no utiliza la devolución de llamada de la solicitud HTTP? – SLaks

+0

No puedo usar esa devolución de llamada porque se puede invocar el renderizado antes de que se devuelva el JSON, o 10 minutos después de que se devuelve. Básicamente, quiero poder invocar render() en cualquier momento que desee. –

+1

Aún puede usar la devolución de llamada. En 'render', compruebe si se ha devuelto el JSON y, si no lo ha hecho, agréguelo a una matriz de devoluciones de llamada. O simplemente use los nuevos objetos Deferred de jQuery, que hace esto por usted. – SLaks

Respuesta

20

Considera:

(function wait() { 
    if (chatroom.json) { 
     chatroom.render(); 
    } else { 
     setTimeout(wait, 500); 
    } 
})(); 

Esto comprobará cada medio segundo.

Demostración en directo:http://jsfiddle.net/kBgTx/

-1

La respuesta que se me ocurrió es así:

var count = 0; 
// Number of functions that need to run. This can be dynamically generated 
// In this case I call check(data, cb) a total of 3 times 
var functionNum = 3; 
function toCallAfter(){ 
    console.log('I am a delayed function'); 
} 

que tenía esto para una función de comprobación que corría una vez regularmente y dos veces en un bucle:

check(data, function(err){ // check is my asynchronous function to check data integrity 
    if (err){ 
     return cb(null, { // cb() is the return function for the containing function 
      errCode: 'MISSINGINFO', 
      statusCode: 403, 
      message : 'All mandatory fields must be filled in' 
     }); 
    } // This part here is an implicit else 
    count++; // Increment count each time required functions complete to 
      // keep track of how many function have completed 
    if (count === functionNum) { 
     return anon(); 
    } 
    return; 
}); 
// Run twice more in a loop 
for(var i = 0; i < 2; i++) { 
    check(data, function(err) { // calls check again in a loop 
     if (err){ 
      return cb(null, { 
       errCode: 'MISSINGINFO', 
       statusCode: 403, 
       message : 'All mandatory fields must be filled in' 
      }); 
     } 
     count++; 
     if (count === functionNum) { 
      return toCallAfter(); 
     } 
     return; 
    }); 
} 

Por último, me gustaría señalar un error de rendimiento significativo en la respuesta alternativa (y extraordinariamente común) ER:

(function wait() { 
    if (chatroom.json) { 
     chatroom.render(); 
    } else { 
     setTimeout(wait, 500); 
    } 
})(); 

En este caso, tiene en sus manos esencialmente el navegador o servidor (Si se utiliza Node.js) como rehenes durante 500 milisegundos para cada cheque que es un tiempo increíblemente largo de un ordenador. Lo que significa un gran golpe de rendimiento. Mi solución de realizar un seguimiento directo de las funciones completas requeridas está libre de restricciones de tiempo y se ejecutará instantáneamente tan pronto como se completen todas las funciones.

+0

500 milisegundos es una vida sí, pero no es así como mantiene el hilo de JS como rehén. Las funciones asíncronas en javascript no bloquean el hilo, se ponen en cola para su ejecución en algún momento en el futuro. La respuesta aceptada es común porque es un javascript idiomático, y es tan eficaz como puedes cuando no tienes un evento "listo" al que puedas responder. –

Cuestiones relacionadas