2012-01-08 24 views
10

Cómo implementar un timeout en Javascript, no el window.timeout sino algo así como session timeout o socket timeout - básicamente - un "function timeout"Cómo implementar una "función de tiempo de espera" en Javascript - no sólo el 'setTimeout'

Un período de tiempo especificado que se dejará transcurrir en un sistema antes de que tenga lugar un evento específico, a menos que ocurra otro evento especificado primero; en cualquier caso, el período finaliza cuando se produce el evento .

concreto, quiero un javascript observing timer que observará el tiempo de ejecución de una función y si se alcanza o ir más de un tiempo determinado, entonces el observing timer se detendrá/notificar a la función de ejecución.

¡Cualquier ayuda es muy apreciada! Muchas gracias.

+0

[ 'window.setTimeout (function_here, number_timeout_milliseconds)'] (https://developer.mozilla.org/en/DOM/window.setTimeout) o 'window.setInterval'? –

+3

No se puede hacer, la función no devolverá el control a nada hasta que finalice. – Esailija

Respuesta

12

No estoy del todo seguro de lo que está preguntando, pero creo que Javascript no funciona de la manera que desea, por lo que no se puede hacer. Por ejemplo, no se puede hacer que una llamada a función normal dure hasta que la operación se complete o una cierta cantidad de tiempo, lo que ocurra primero. Eso se puede implementar fuera de javascript y expuesto a través de javascript (como se hace con llamadas ajax sincrónicas), pero no se puede hacer en javascript puro con funciones regulares.

A diferencia de otros idiomas, Javascript tiene un solo hilo para que mientras se ejecuta una función nunca se ejecute un temporizador (excepto para los trabajadores de la web, pero están muy, muy limitados en lo que pueden hacer). El temporizador solo se puede ejecutar cuando la función termina de ejecutarse. Por lo tanto, ni siquiera puede compartir una variable de progreso entre una función síncrona y un temporizador, por lo que no hay forma de que un temporizador "controle" el progreso de una función.

Si su código fue completamente independiente (no accedió a ninguna de sus variables globales, no llamó a sus otras funciones y no accedió al DOM de todos modos), entonces podría ejecutarlo en una web- trabajador (disponible solo en los navegadores más nuevos) y utiliza un temporizador en el hilo principal. Cuando el código del trabajador web se completa, envía un mensaje al hilo principal con sus resultados. Cuando el hilo principal recibe ese mensaje, detiene el temporizador. Si el temporizador se dispara antes de recibir los resultados, puede matar al trabajador web. Pero, su código tendría que vivir con las restricciones de los trabajadores web.

Soemthing también se puede hacer con las operaciones asincrónicas (porque trabajan mejor con-un único subproceso dad de Javascript) así:

  1. iniciar una operación asíncrona como una llamada AJAX o la carga de una imagen.
  2. Inicie un temporizador usando setTimeout() para su tiempo de espera.
  3. Si el temporizador se dispara antes de que se complete su operación asincrónica, entonces detenga la operación asincrónica (utilizando las API para cancelarla).
  4. Si la operación asíncrona se completa antes de que se dispare el temporizador, cancele el temporizador con clearTimeout() y continúe.

Por ejemplo, aquí es cómo poner un tiempo de espera en la carga de una imagen:

function loadImage(url, maxTime, data, fnSuccess, fnFail) { 
    var img = new Image(); 

    var timer = setTimeout(function() { 
     timer = null; 
     fnFail(data, url); 
    }, maxTime); 

    img.onLoad = function() { 
     if (timer) { 
      clearTimeout(timer); 
      fnSuccess(data, img); 
     } 
    } 

    img.onAbort = img.onError = function() { 
     clearTimeout(timer); 
     fnFail(data, url); 
    } 
    img.src = url; 
} 
1

Todo esto es posible sólo con algunos trucos incondicionales.Como por ejemplo, si usted sabe qué tipo de variable de sus declaraciones de función (tenga en cuenta que cada función JS vuelve algo, por defecto es undefined), puede intentar algo como esto: definir la variable

var x = null; 

y ejecutar la prueba en particular " hilo ":

function test(){ 
    if (x || x == undefined) 
     console.log("Cool, my function finished the job!"); 
    else 
     console.log("Ehh, still far from finishing!"); 
} 
setTimeout(test, 10000); 

y función, finalmente, ejecutar:

x = myFunction(myArguments); 

Esto sólo funciona si usted sabe que su función no devuelve ningún valor (es decir el valor devuelto es undefined) o el valor que devuelve siempre es "no falso", es decir, no se convierte a la declaración false (como 0, null, etc.).

+0

A diferencia de otros idiomas, Javascript no tiene subprocesos que pueden compartir libremente variables con otras funciones de ejecución. Tiene trabajadores web, pero solo pueden comunicarse con el hilo principal a través de mensajes, no compartiendo variables. – jfriend00

-1

Comparta una variable entre observing timer y executing function.

Implemente el observing timer con window.setTimeout o window.setInterval. Cuando se ejecuta observing timer, establece un valor exit en la variable compartida.

El executing function comprueba constantemente el valor de la variable .. y lo devuelve si se especifica exit value.

+1

'setTimeout' solo garantiza un retraso mínimo, si' execute function' aún se está ejecutando cuando expira el tiempo de espera, la 'función de observación' solo se llamará una vez que se complete' execute function'. Tendrá que implementar una versión JS de 'DoEvents' para que esta solución funcione. – Douglas

+0

Nunca se ejecutará un temporizador mientras se está ejecutando una función de ejecución porque javascript es de subproceso único. El temporizador SOLO puede activarse después de que la función termine de ejecutarse. Por lo tanto, no creo que esto pueda funcionar. Si piensas lo contrario, crea un jsFiddle que muestre esto. – jfriend00

+0

Tienes razón. Pensando en ello, si HTML5 es una opción, el uso de un trabajador puede ser una solución posible. ¿Qué piensas? –

2

Puede ejecutar el código en un trabajador web. Entonces aún puede manejar eventos de tiempo de espera mientras el código se está ejecutando. Tan pronto como el trabajador web finalice su trabajo, puede cancelar el tiempo de espera. Y tan pronto como se agote el tiempo de espera, puede finalizar el trabajador web.

execWithTimeout(function() { 
    if (Math.random() < 0.5) { 
     for(;;) {} 
    } else { 
     return 12; 
    } 
}, 3000, function(err, result) { 
    if (err) { 
     console.log('Error: ' + err.message); 
    } else { 
     console.log('Result: ' + result); 
    } 
}); 

function execWithTimeout(code, timeout, callback) { 
    var worker = new Worker('data:text/javascript;base64,' + btoa('self.postMessage(' + String(code) + '\n());')); 
    var id = setTimeout(function() { 
     worker.terminate(); 
     callback(new Error('Timeout')); 
    }, timeout); 
    worker.addEventListener('error', function(e) { 
     clearTimeout(id); 
     callback(e); 
    }); 
    worker.addEventListener('message', function(e) { 
     clearTimeout(id); 
     callback(null, e.data); 
    }); 
} 
Cuestiones relacionadas