2010-06-28 56 views
14

Supongamos que quiero bloquear la ejecución de Javascript durante un tiempo determinado por algún motivo extraño, ¿cómo puedo hacer eso? No hay sueño() en JS. Los pls no dicen hacer un ciclo while() porque eso es malo. Puedo hacer un window.showModalDialog y poner una ventana.close en el diálogo modal con setTimeout de muy poco tiempo para que el usuario no note el diálogo. Esto será como dormir durante un período de tiempo pequeño y puedo llamar a esto varias veces si es necesario. ¿Hay alguna otra manera?sleep() en Javascript

Para elaborar, mi caso de uso es que HTML5 SQL Database ha dado api asíncronas, pero quiero usarlo para una aplicación web para la que la tienda nunca será grande. Por lo tanto, no hay necesidad de una API asíncrona porque las consultas en la tienda pequeña se ejecutarán en el lado del cliente. Así que quiero escribir un ORM con API de sincronización para que los desarrolladores puedan usarlo más fácilmente. Para cerrar esta sincronización para sincronizar la API, necesito algo así como dormir.

+1

¿Puedes exponer un poco tu ejemplo? Parece que 'setInterval()' es lo que buscas, pero no estoy 100% claro en tu caso de uso. –

Respuesta

13

window.setTimeout o window.setInterval son prácticamente tus únicos amigos.

Un ejemplo de cómo utilizar setTimeout llamar recursivamente una función que establece otro tiempo de espera es el siguiente

function go() { 
    if (go.count < 4) { 
     // logs 1, 2, 3 to firebug console at 1 second intervals 
     console.log(go.count++); 
     window.setTimeout(go, 1000); 
    } 
} 
go.count = 1; 

go(); 

Usted puede elegir para capturar la timeoutID de usar con window.clearTimeout si es necesario borrar el tiempo de espera antes de la terminando.

Tenga en cuenta que ni window.setTimeout ni window.setInterval bloquean la ejecución de otro script - No creo que esto sea posible con JavaScript en su versión actual. Hay formas que se pueden codificar para imitar el bloqueo de la interfaz de usuario, como usar showModalDialog o tener algún booleano global blocking que sea lo más parecido posible, me temo.

+4

Esto ya está en la pregunta :) –

+1

-1: Ya está en la pregunta. ¿Y QUIÉN subió de categoría esto? – naiad

+1

cierto, está en la pregunta, pero es más o menos la respuesta de JavaScript a 'Thread.Sleep()'/'Insert language equivalent'. –

9

@Russ Cam es correcto, setTimeout es lo que estás buscando. La forma en que lo mencionas en la pregunta, sin embargo, me hace pensar que podría haber cierta confusión sobre cómo se usa.

No bloqueará la ejecución del bloque en el que se encuentra, sino que llamará a su función de entrada después de un cierto intervalo. A modo de ejemplo:

function illustration() { 
    // start out doing some setup code 
    alert("This part will run first"); 

    // set up some code to be executed later, in 5 seconds (5000 milliseconds): 
    setTimeout(function() { 
    alert("This code will run last, after a 5 second delay") 
    }, 5000); 

    // This code will run after the timeout is set, but before its supplied function runs: 
    alert("This will be the second of 3 alert messages to display"); 
} 

verá tres mensajes de alerta cuando se ejecuta esta función, con un retraso entre la segunda y tercera:

  1. "Esta parte se ejecutará primero"
  2. "Esta será el segundo de 3 mensajes de alerta para visualizar"
  3. 'Este código se ejecutará pasado, después de un retraso de 5 segundos'
+0

Sí, lo entiendo pero quiero bloquear la ejecución, por lo que setTimeout no ayuda. – nomind

+1

Si quiere bloquear la ejecución, entonces 'while' es lo que quiere, pero esto congelará el navegador (porque está bloqueando la ejecución). Dudo que realmente quieras bloquear la ejecución. – pkaeding

3

Esta respuesta puede ser un poco molesta pero desnuda :-).

Como javascript normalmente se ejecuta dentro de un navegador, que tiene varios subprocesos y javascript puede ocupar varios subprocesos, no existe el concepto de "inactividad global" como lo haría en un programa con subprocesos individuales.

Si desea pausar una operación de manera razonable, es posible que desee considerar lo siguiente.

Digamos que usted quiere a la siguiente

function foo(s) { 
    var j = 1; var k = 1; 
    sleep(s); // This would be nice right? 
    window.alert("Sum is : " + (j+k)); 
} 

En realidad se convierte en:

function foo(s) { 
    var j = 1 ; var k = 1; 
    setTimeout(s, function() { 
      window.alert("Sum is : " + (j+k)); 
    }); 
} 

Por supuesto, el problema es que en un sentido procesal es posible que desee tener algo como

function foo() { 
    do stuff; 
    pause(); 
    do more stuff; 
    return; 
} 

function bar() { 
     foo(10); 
     window.alert("I want this to happen only after foo()"); 
} 

El problema es que no se puede hacer eso usando setTimeout, como se muestra arriba

Sin embargo, usted puede hacer algo como:

function foo(s, afterwards, afterparms) { 
    var j = 1 ; var k = 1; 
    setTimeout(s, function() { 
      window.alert("Sum is : " + (j+k)); 
      afterparms.parm1 = afterparms.parm1.toUpperCase(); 
      afterwards(afterparms); 
    }); 
} 

function bar() { 
     foo(10, function() { 
      window.alert("This will happen after window.alert"); 
     }, { parm1: 'hello', parm2: 'world' }); 
} 

Tenga en cuenta que por encima es sólo una manera de ir sobre la transmisión de información a las funciones, puede hacer algunas cosas realmente buenas, si miras hacia arriba convenciones función de llamada, argumentos variables y tales

Esto es molesto de programar si usted piensa proceduralmente. Sin embargo, hay dos cosas para recordar con respecto a javascript. NO es un lenguaje de procedimiento, NI es un lenguaje orientado a objetos. Javascript es un lenguaje funcional con un sofisticado modelo de gestión de eventos. Entonces debes pensar en esos términos.

Tiene sentido también, ya que la máquina javascript típica es una interfaz gráfica de usuario (navegador web) que, por diseño, no desea bloquear completamente al intentar procesar algo. Imagina que tu navegador se bloquea por completo mientras una página está haciendo algo, querrás estrangular al programador que te hace eso.

El código de JavaScript debe ser de naturaleza 'ignórete y olvídate', y si las cosas tienen que esperar a que ocurra un evento antes de continuar, entonces deberías mirar el modelo de eventos de JavaScript.

Si bien esto es una programación inconveniente cuando se quiere hacer algo trivial, es probable que esté usando pausa para esperar de una manera que pueda correr en condiciones de carrera, y que hay una forma más apropiada de hacerlo. "efecto" que estás tratando de lograr.

Si publica su caso PARTICULAR, puede haber más información próxima sobre cómo se puede abordar tal situación.

Saludos,

+0

Incorrecto. JS NO ejecuta multiproceso. setTimeout tampoco hace lo que pide la pregunta. Ver mi respuesta para más detalles. – selfawaresoup

+0

JavaScript tiene un único subproceso. Y también lo son muchos navegadores. –

+0

Agradezco todos sus comentarios. He actualizado la pregunta con mi caso de uso, si eso justifica la necesidad de dormir(). – nomind

3

puedo hacer un window.showModalDialog y poner un window.close en el diálogo modal con setTimeout de tiempo muy pequeño

Eso es inventiva, pero sólo se permite para el usuario interacción con cualquier cosa en el cuadro de diálogo modal, durante el tiempo que está abierto. El resto del navegador permanece colgado tan seguro como si acabaras de llamar a un brutal lazo while (new Date().getTime()<t1);.

El diálogo modal es más amable en ciclos de CPU y evitará desencadenar el watchdog de tiempo de ejecución de scripts en el caso de esperas largas, pero tendría que equilibrar eso con la molestia de un cuadro de diálogo intermitente que distrae, y el soporte de navegador no universal, y el tema de todos los que odian los diálogos modales.

Esto será como dormir durante un período de tiempo pequeño y puedo llamar a esto varias veces si es necesario. ¿Hay alguna otra manera?

¿Qué estás tratando de lograr durmiendo? Sin volver al ciclo de eventos o activar un cuadro de diálogo modal, no obtendrá ninguna actualización en pantalla o interacción del usuario, por lo que no veo qué efecto tendrá en usted el sueño en línea. Ciertamente no puedes hacer animación de esta manera.

En Firefox obtienes el estilo de Python generators, que te permite escribir un proceso de interacción de estilo de procedimiento usando yield para devolver el control al navegador según sea necesario. Esto puede mejorar la simplicidad del código ya que no tiene que volver a escribir las estructuras condicionales y de bucle como estado recordado en las variables. Sin embargo, como solo los navegadores Mozilla lo admiten, no puedes usarlo en la naturaleza en un futuro cercano.

ETA:

Quiero escribir un ORM con la API de sincronización para que los desarrolladores pueden utilizar más fácilmente. Para cerrar esta sincronización para sincronizar la API, necesito algo así como dormir.

Lo sentimos, no se puede hacer en el caso general. JavaScript básico no tiene subprocesos, co-rutinas u otras primitivas que pueden puentear la sincronización y el código asincrónico.

La especificación de la base de datos web SQL se basa en navegadores que invocan la función de gestión de resultados (que se pasa al executeSql()) como una devolución de llamada del navegador. Las devoluciones de llamada del navegador solo pueden activarse cuando el control ha vuelto al navegador, no dentro de un hilo de ejecución síncrono.

En teoría, se podría abrir una ModalDialog, hacer la llamada asíncrona de base de datos SQL Web dentro ventana de la modalDialog 's, y tienen la ModalDialog devuelve el resultado al código sincrónico de secuencias de comandos de la ventana de llamadas. Sin embargo, actualmente no hay ningún navegador compatible con openDatabaseyopenModalDialog!

+0

Consulte el caso de uso en la pregunta actualizada, si eso justifica la necesidad. Pero hay problemas con mi enfoque showModalDialog, incluso si lo cierro, digamos dentro de los 10 ms, podría aparecer en máquinas lentas (¿es esto posible?) Y el foco no volvería al lugar correcto en la ventana principal. – nomind

+0

@nomind: se agregó información inútil. Quizás si los navegadores futuros implementan tanto diálogos modales como SQL juntos, podría ser factible, pero además de los problemas de actualizar la ventana, requeriría que los usuarios desactivaran sus bloqueadores de ventanas emergentes. Creo que vas a tener que vivir con un código asíncrono y funciones de devolución de llamada. O simplemente use el back-end síncrono 'localStorage' más ampliamente soportado en lugar de exótico' openDatabase': para una 'pequeña aplicación web' con acceso de estilo de objeto, las características de una base de datos relacional no le ayudarán en absoluto. – bobince

+0

No estoy de acuerdo. Cualquier navegador basado en webkit como google chrome tiene tanto showModalDialog como openDatabase – nomind

6

Para aclarar: La cuestión es detener por completo la ejecución del script durante un cierto período de tiempo, no retrasar la ejecución de algún fragmento de código, que será una tarea para setTimeout o setInterval.

Una implementación limpia de sleep() simplemente no es posible y tampoco es deseable en JavaScript.

setTimout y setInterval NO detiene la ejecución de la secuencia de comandos como algunas personas aquí parecen pensar mejor. Simplemente registra una función que se ejecutará pospuesta. El resto del script continuará ejecutándose mientras el tiempo de espera/intervalo esté esperando.

Debido a la naturaleza asíncrona de JavaScript, la única forma de "bloquear" cualquier ejecución de código sería muy desagradable y ABSOLUTAMENTE NO RECOMENDADO mientras el ciclo se ejecuta durante un período de tiempo determinado. Dado que JavaScript se ejecuta en un solo hilo (no estamos hablando de WebWorkers API aquí ...). Esto detendría la ejecución de cualquier código JS hasta que termine ese ciclo. Pero ese es el estilo realmente malo ...

Si su programa no puede funcionar sin algo como sleep(), tal vez debería reconsiderar su enfoque.

1

Sé que esta pregunta es un poco antigua, pero tuve un problema similar cuando tuve que simular un script que tardó mucho tiempo en cargarse en la página. Terminé resolviendo el problema creando un punto final del lado del servidor que esperó 5 segundos antes de enviar la respuesta, luego agregué una etiqueta de script al DOM para señalar esto.

Otorgado requiere una implementación del lado del servidor, sin embargo, le permite detener la página en cualquier punto específico. Como otros han dicho antes, esto bloqueará todo el navegador, no solo su script.