¿Cuál es la versión JavaScript de sleep ()?

2907

¿Hay una mejor manera de diseñar un sleepen JavaScript que la siguiente pausecompfunción ( tomada de aquí )?

function pausecomp(millis)
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}

Esto no es un duplicado de Sleep en JavaScript: retraso entre acciones ; Quiero un sueño real en medio de una función, y no un retraso antes de que se ejecute un fragmento de código.

7
  • 6
    Se configura en el medio de un tiempo, si uso setTimeout, el while continuará procesando y poniendo en cola más setTimeouts que eventualmente se ejecutarán al mismo tiempo y harán un poco de simultaneidad entre ellos.
    fmsf
    4 de junio de 2009 a las 14:44
  • 210
    Esta es una solución horrible: estará masticando los ciclos de procesamiento sin hacer nada. 4 jun 09 a las 14:47
  • 14
    El único propósito de una suspensión es sondear o esperar una devolución de llamada: setInterval y setTimeout hacen ambas cosas mejor que esto. 4 jun 09 a las 14:50
  • 1
    Probablemente pueda hacer lo que quiera con la continuación del estilo de paso en JavaScript. Eche un vistazo a este artículo. 15 de mayo de 2015 a las 8:02
  • 18
    Es asombroso ver a la gente decir que no sin entender lo que quiere el OP. Hay casos en los que quieres dormir de verdad . Ahora necesito un sueño real para probar el comportamiento de los navegadores al publicar y recibir mensajes entre la ventana superior y el iframe. Mantenerlo ocupado con while parece la única forma. 6 de junio de 2020 a las 4:18
3754

Actualización 2017-2021

Desde 2009, cuando se hizo esta pregunta, JavaScript ha evolucionado significativamente. Todas las demás respuestas ahora son obsoletas o demasiado complicadas. Aquí está la mejor práctica actual:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo() {
  console.log('Taking a break...');
  await sleep(2000);
  console.log('Two seconds later, showing sleep in a loop...');

  // Sleep in loop
  for (let i = 0; i < 5; i++) {
    if (i === 3)
      await sleep(2000);
    console.log(i);
  }
}

demo();

Eso es todo. await sleep(<duration>).

O como una sola línea:

await new Promise(r => setTimeout(r, 2000));

Tenga en cuenta que,

  1. awaitsolo se puede ejecutar en funciones con el prefijo de la asyncpalabra clave, o en el nivel superior de su script en un número creciente de entornos .
  2. awaitsolo pausa la asyncfunción actual . Esto significa que no está bloqueando la ejecución del resto del script, que es lo que desea en la gran mayoría de los casos. Si desea una construcción de bloqueo, vea esta respuesta usando , pero tenga en cuenta que la mayoría de los navegadores no lo permitirán en el hilo principal del navegador.Atomics.wait

Dos nuevas funciones de JavaScript (a partir de 2017) ayudaron a escribir esta función de "suspensión":

Compatibilidad

Si, por alguna extraña razón, está utilizando un Node anterior a 7 (que ha llegado al final de su vida útil ), o está apuntando a navegadores antiguos, async/ awaitaún se puede usar a través de Babel (una herramienta que transpilará JavaScript + nuevas funciones en JavaScript simple y antiguo) , con el transform-async-to-generatorcomplemento.

37
  • 7
    Grandes cosas aquí. Me pregunto, ¿cómo afecta esto o se relaciona con los estados "activo" / "inactivo" de los navegadores modernos después de que JS llama al modo de "suspensión"? ¿Puede el navegador bloquear la suspensión como se esperaba para JS general, para recordar más tarde cuando se vuelve "activo", o tiene un comportamiento diferente? 12/10/2016 a las 2:16
  • 23
    ¿Cuál es el soporte actual del navegador para esto? No consideraría "obsoletas" las soluciones anteriores hasta que esta solución sea compatible con la gran mayoría de los navegadores, o al menos con todos los habituales. Por el contrario, consideraría esta solución interesante pero inutilizable / impráctica hasta que tenga un apoyo generalizado. 27/12/2016 a las 17:56
  • 4
    @jacroe: el transpiler maneja las funciones de flecha, así como async / await (lo que haría que IE vomitara sangre de todos modos) 30 de mayo de 2017 a las 8:39
  • 17
    @niry JavaScript, al ser un lenguaje de un solo subproceso, no es adecuado para el sueño "real", ya que se ejecuta en el mismo subproceso que la interfaz de usuario y provocaría que las páginas web no respondan. 13/09/18 a las 14:18
  • 11
    @PatrickRoberts, estoy de acuerdo. Sin embargo, esa era la cuestión, con mucha claridad.
    niry
    13/09/18 a las 21:41
856

(Consulte la respuesta actualizada para 2016 )

Creo que es perfectamente razonable querer realizar una acción, esperar y luego realizar otra acción. Si está acostumbrado a escribir en lenguajes de subprocesos múltiples, probablemente tenga la idea de ceder la ejecución durante un período de tiempo determinado hasta que su subproceso se active.

El problema aquí es que JavaScript es un modelo basado en eventos de un solo hilo. Si bien en un caso específico, puede ser bueno que todo el motor espere unos segundos, en general es una mala práctica. Supongamos que quisiera hacer uso de sus funciones mientras escribía las mías. Cuando llamé a su método, todos mis métodos se congelaron. Si JavaScript pudiera de alguna manera preservar el contexto de ejecución de su función, almacenarlo en algún lugar, luego traerlo de vuelta y continuar más tarde, entonces podría suceder el sueño, pero eso básicamente sería enhebrar.

Por lo tanto, está bastante atascado con lo que otros han sugerido: deberá dividir su código en múltiples funciones.

Entonces, tu pregunta es una elección un poco falsa. No hay forma de dormir de la manera que desea, ni debe buscar la solución que sugiere.

6
  • 57
    Esta no es una respuesta correcta en absoluto. Si Javascript no tiene una función de suspensión, es solo porque ECMAScript no la requiere. Es una elección de diseño por parte del organismo responsable del diseño de Javascript. Se podría haber hecho que el tiempo de ejecución de Javascript espere una cantidad determinada de tiempo antes de ejecutar la siguiente línea de código, pero se decidió no hacerlo. 16/0813 a las 19:20
  • 5
    Un sueño se puede implementar perfectamente en JavaScript, pero no con precisión en tiempo real. Después de todo, es un sistema basado en eventos. Si se completan las llamadas asíncronas, se activa un evento. No veo ninguna razón por la que no pueda ser posible lo mismo cuando se emite un sleep () después del cual el control se devuelve al navegador hasta que finaliza el sleep, devolviendo el control a la función de llamada. Y sí, también estoy de acuerdo en que a veces dormir es útil, especialmente cuando los desarrolladores ANTES de que arruinaras tanto el diseño que no tienes otra salida además de refactorizar por completo para lo cual no tienes tiempo. 14/11/2013 a las 12:40
  • Prueba Hypnotic, que sigue esta idea: coolwanglu.github.io/hypnotic/web/demo.html
    Tezcat
    5 de diciembre de 2013 a las 10:34
  • 4
    Llamar a javascript de un solo subproceso es un mito. Si bien puede ser técnicamente correcto, funcionalmente actúa como un lenguaje multiproceso. Simular un fork () es trivialmente fácil, y aunque yield () no es realmente implementable, puede acercarse bastante usando la memoria compartida para bloquear / semáforo. Para el programador promedio, tiene sentido tratarlo como multiproceso; el nombre técnico solo les importa a los desarrolladores del lenguaje. 29/01/15 a las 15:06
  • 11
    Estoy de acuerdo por qué sleep()no es posible en JS y que la mayoría de las veces hay mejores formas de hacer las cosas. Pero todavía consideraría la forma en que el motor une todas las cosas como un defecto de diseño; No hay razón para que el lenguaje no pueda tener una sleep()función limitada a un script, página o función específicos sin que el motor golpee la CPU y congele la aplicación como un loco. Es 2015 y no debería poder bloquear un navegador web completo con while(1). Tenemos Flash para cosas así.
    Beejor
    12/09/15 a las 5:10
713

En JavaScript, reescribo cada función para que pueda finalizar lo antes posible. Quiere que el navegador vuelva a tener el control para que pueda realizar cambios en el DOM.

Cada vez que quería dormir en medio de mi función, refactorizaba para usar un setTimeout().

Editar

La infame función del sueño, o retraso, dentro de cualquier idioma es muy debatida. Algunos dirán que siempre debe haber una señal o devolución de llamada para activar una funcionalidad determinada, otros argumentarán que a veces es útil un momento arbitrario de retraso. Les digo que a cada uno lo suyo y una sola regla nunca puede dictar nada en esta industria.

Escribir una función de suspensión es simple y aún más utilizable con JavaScript Promises:

// sleep time expects milliseconds
function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

// Usage!
sleep(500).then(() => {
    // Do something after the sleep!
});
21
  • 192
    A modo de cierre. function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); }
    chaos
    8 de abril de 2010 a las 3:27
  • 71
    ok, ¿y si el código no está destinado a ser utilizado en una página web? 22/07/10 a las 15:23
  • 11
    @ EugenioMiró si el código no está destinado a ser utilizado en una página web, haga que el modelo de objetos del host implemente un método de suspensión. - Creo que la pregunta está orientada al DOM que está expuesto a javascript que se ejecuta en páginas web. 24 de septiembre de 2011 a las 0:57
  • 32
    @Nosredna sí, entendemos cómo hacer llamadas asíncronas, esto no nos ayuda a dormir (). Quiero que mis llamadas se realicen en un orden determinado y que los datos se recuperen en un orden determinado. Estoy a 5 niveles de profundidad en un bucle for. Quiero BLOQUEAR la ejecución. Un verdadero método de suspensión no "ralentizaría el navegador", el control de manos de suspensión no volvería al navegador ni a ningún otro hilo que desee tiempo de CPU mientras aún está bloqueado. 24 de septiembre de 2011 a las 0:59
  • 388
    esta no es una respuesta a la pregunta.
    Tomas
    24/11/11 a las 13:22
333

En Firebug (y probablemente en otras consolas de JavaScript), no sucede nada después de presionar enter, solo después de la duración de suspensión especificada (...)

function sleepFor(sleepDuration){
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ /* Do nothing */ }
}

Ejemplo de uso:

function sleepFor(sleepDuration){
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ 
        /* Do nothing */ 
    }
}

function sleepThenAct(){
    sleepFor(2000);
    console.log("Hello, JavaScript sleep!");
}

sleepThenAct()

Nota: solo para depuración y desarrollo

14
  • 45
    Ésta no es una respuesta. Es exactamente el mismo que el código de la pregunta, excepto que es un poco más corto.
    jab
    2 de junio de 2015 a las 4:23
  • 26
    Ocupado esperando, ¿de verdad? ¿En JS? ¿Por segundos? Si descubro que un sitio web está haciendo esto, se bloqueará.
    mafu
    19/08/2016 a las 12:27
  • 45
    @mafu Por eso dice only for debug/dev... rolleyes
    xDaizu
    29 de agosto de 2016 a las 10:31
  • 22
    NUNCA HAGA ESTO. Esto hará que la CPU alcance el 100% del núcleo que ejecuta y lo bloqueará.
    eaorak
    18 dic 2017 a las 10:51
  • 5
    Esto es útil, y quizás la ÚNICA forma de dormir, dentro de una aplicación javascript de línea de comandos, porque async / await no es útil.
    Wheezil
    13/01/18 a las 18:52
185

Estoy de acuerdo con los otros carteles. Un sueño intenso es simplemente una mala idea.

Sin embargo, setTimeout no detiene la ejecución. Ejecuta la siguiente línea de la función inmediatamente después de que se establece el tiempo de espera, no después de que expira el tiempo de espera, por lo que no logra la misma tarea que realizaría una suspensión.

La forma de hacerlo es dividir su función en partes antes y después.

function doStuff()
{
  // Do some things
  setTimeout(continueExecution, 10000) // Wait ten seconds before continuing
}

function continueExecution()
{
   // Finish doing things after the pause
}

Asegúrese de que los nombres de sus funciones aún describan con precisión lo que está haciendo cada pieza (es decir, GatherInputThenWait y CheckInput, en lugar de funcPart1 y funcPart2)

Este método logra el propósito de no ejecutar las líneas de código que decida hasta después de su tiempo de espera, mientras que aún devuelve el control a la PC cliente para ejecutar cualquier otra cosa que haya puesto en cola.

Como se señaló en los comentarios, esto no funcionará en un bucle. Podrías hacer algún truco elegante (feo) para que funcione en un bucle, pero en general eso solo generará un código espagueti desastroso.

10
  • 12
    Sí. Donde esto se vuelve complicado es cuando tienes un bucle, o incluso un bucle anidado. Tienes que abandonar tus bucles for y tener contadores en su lugar. 4 de junio de 2009 a las 15:10
  • Touché. Quiero decir, todavía sería posible, pero feo y hack en ese caso. También podría usar algunas variables de estado booleanas estáticas, pero eso también es bastante complicado.
    DevinB
    4 de junio de 2009 a las 15:20
  • 3
    -1 para esto. Una vez más, esto no responde a la pregunta. Esta es más una respuesta a una pregunta como "Cómo ejecutar una función de forma asincrónica", que es muy diferente de "Cómo bloquear la ejecución de un código". 28 de enero de 2013 a las 8:32
  • 6
    @Nosredna No, usarías un cierre. Por ejemplo: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); }y for(var X = 0; X < 3;X++) { foo(X); }- se pasa el valor de X foo, que luego se reutiliza con el nombre indexcuando foo_continuefinalmente se llama.
    Izkata
    13/01/2014 a las 19:34
  • 2
    @Alexander Por supuesto que sí, porque el objetivo de setTimeout () es evitar que el navegador se bloquee ejecutando el código de forma asincrónica. Ponga el console.log()interior foo_continue()en la versión setTimeout y obtendrá el mismo resultado.
    Izkata
    23/03/15 a las 14:20
140

Por el amor de $ DEITY, no hagas una función de espera ocupada y espera. setTimeouty setIntervalhaz todo lo que necesites.

var showHide = document.getElementById('showHide');
setInterval(() => {
    showHide.style.visibility = "initial";
    setTimeout(() => {
        showHide.style.visibility = "hidden"
    }, 1000);
    ;
}, 2000);   
<div id="showHide">Hello! Goodbye!</div>

Cada intervalo de dos segundos oculta el texto durante un segundo. Esto muestra cómo usar setInterval y setTimeout para mostrar y ocultar texto cada segundo.

13
  • 3
    Bueno, no todo: setInterval da una mejor impresión de las encuestas. 4 jun 09 a las 14:48
  • 3
    ¿Qué no retendría ese fragmento de código en el motor de JavaScript? 4 de junio de 2009 a las 14:51
  • 13
    A menos que necesite que el sueño sea sincrónico, en cuyo caso esta es una pregunta completamente válida. 21/09/11 a las 16:54
  • 44
    Creo que muchos de nosotros podríamos estar olvidando que JavaScript no es un lenguaje exclusivo para navegadores. Este tipo podría estar creando una utilidad de línea de comandos de Node que requiere una breve pausa sin necesidad de lidiar con todos los problemas de alcance de variables que vienen con setTimeout. 2 mar 14 a las 12:07
  • 3
    @PhilLaNasa: Si el cierre sintáctico todavía asusta a uno, es necesario abrocharse el cinturón y trabajar en el Nodo 101.
    chaos
    3/0314 a las 16:47
111

Si (como yo) está usando JavaScript con Rhino , puede usar ...

try
{
  java.lang.Thread.sleep(timeInMilliseconds);
}
catch (e)
{
  /*
   * This will happen if the sleep is woken up - you might want to check
   * if enough time has passed and sleep again if not - depending on how
   * important the sleep time is to you.
   */
}
3
  • 4
    ¿Es esta una llamada a Java? 12 mar.15 a las 23:02
  • 25
    Esto es Java, no Javascript 31/01/18 a las 14:39
  • 26
    @RousseauAlexandre Incorrecto. Es JavaScript usando Rhino (en ese momento, también podría ser Nashorn en estos días) 1 feb 2018 a las 20:42
72

Si está usando jQuery, alguien realmente creó un complemento de "demora" que no es más que un contenedor para setTimeout:

// Delay Plugin for jQuery
// - http://www.evanbot.com
// - © 2008 Evan Byrne

jQuery.fn.delay = function(time,func){
    this.each(function(){
        setTimeout(func,time);
    });

    return this;
};

Luego puede usarlo en una fila de llamadas a funciones como se esperaba:

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');
4
  • 4
    Esa no es una mala solución. Mantiene el contexto y la encadenabilidad. 10 jun 09 a las 19:00
  • 40
    A partir de jQuery 1.4, .delay()es parte de jQuery (aunque con una semántica diferente a la implementación anterior). api.jquery.com/delay 24/10/11 a las 13:26
  • 9
    Lo que definitivamente le faltaba a esta pregunta era una respuesta de jQuery . ¡Me alegro de haberlo conseguido!
    xDaizu
    30 de agosto de 2016 a las 8:56
  • 1
    Si necesita un retraso entre dos llamadas independientes, sí. Si necesita retrasos para ralentizar un bucle, no. 31 de mayo de 2018 a las 21:43
49

También busqué una solución de suspensión (no para código de producción, solo para desarrollo y pruebas) y encontré este artículo:

JavaScript dormir () o esperar ()

... y aquí hay otro artículo con soluciones del lado del cliente: suspensión de JavaScript

Además, cuando llame alert(), su código también se pausará, mientras se muestra la alerta; debe encontrar una manera de no mostrar la alerta, pero obtener el mismo efecto. :)

1
  • 40
    Estoy de acuerdo, mucha gente dice: "¡No, no hagas esto en el código de producción!" Sí, no quiero. Quiero hacerlo en código de prueba desechable y, como resultado, no quiero perder mucho tiempo creando una solución elegante. 17/10/12 a las 15:03
38

Usar:

  await new Promise(resolve => setTimeout(resolve, 2000));

Asegúrese de que su función de llamada sea asincrónica. Esto está verificado y funciona bien.

2
  • 1
    Finalmente. La única respuesta. 22 de mayo de 2020 a las 9:29
  • Esta es una respuesta realmente excelente y simple. ¡Gracias por compartir! 10 de marzo a las 3:42
31

Aquí tienes. Como dice el código, no seas un mal desarrollador y utilízalo en sitios web. Es una función de utilidad de desarrollo.

// Basic sleep function based on ms.
// DO NOT USE ON PUBLIC FACING WEBSITES.
function sleep(ms) {
    var unixtime_ms = new Date().getTime();
    while(new Date().getTime() < unixtime_ms + ms) {}
}
2
  • 19
    Eso es básicamente lo mismo que tenía el OP. 3 de noviembre de 2012 a las 2:16
  • 8
    Para ser más precisos, es a lo que OP pidió una ALTERNATIVA. 25 de mayo de 2018 a las 20:48
30

Aquí hay una solución simple que usa un XMLHttpRequest sincrónico:

function sleep(n){
  var request = new XMLHttpRequest();
  request.open('GET', '/sleep.php?n=' + n, false);  // `false` makes the request synchronous
  request.send(null);
}

Contenido del archivo sleep.php :

<?php sleep($_GET['n']);

Ahora llámalo con:

sleep(5);
5
  • 5
    @lukad, Úselo setTimeout()si eso funciona, pero si hacerlo significa desentrañar 1000 líneas de devoluciones de llamada, esto podría comenzar a no parecer una broma. 25/12/14 a las 1:01
  • 12
    Enfoque único, aunque lamentablemente las XMLHttpRequests no asíncronas están en desuso y se eliminarán en el futuro. Lo cual es gracioso, porque ese hecho es lo que me llevó a esta pregunta en primer lugar.
    Beejor
    14 jun 15 a las 20:30
  • En realidad, esta es una idea bastante buena, en mi opinión. Aunque no creo que la API de suspensión (URL de solicitud) deba ser pública, ya que se puede abusar de ella. 12 de mayo de 2016 a las 13:18
  • @Beejor pensar siempre solo en el futuro significa vivir en la irrealidad futurista :-) 20/02/20 a las 10:28
  • bueno, pero ¿sabe si en algún momento Internet es lento o el tiempo de ping del sitio web es alto, entonces dormirá el script por más de un tiempo de discusión? Por ejemplo, si utiliza un sleep(300)sitio web que tarda 150 ms en responder, el código javascript estará inactivo durante 450 ms. y si el navegador pierde la conexión a Internet, funcionará solo por 0 ms. Entonces no es mejor solución 24 abr.20 a las 10:52
23

Primero:

Defina una función que desee ejecutar así:

function alertWorld(){
  alert("Hello, World!");
}

Luego programe su ejecución con el método setTimeout :

setTimeout(alertWorld, 1000)

Nota dos cosas

  • el segundo argumento es el tiempo en milisegundos
  • como primer argumento, debe pasar solo el nombre (referencia) de la función, sin los paréntesis
1
  • La cuestión era preguntar una forma de dormir en una vía de bloqueo. setTimeout no hace eso. Se pone en cola en la cola de tareas de macro. 28 mar a las 21:20
23

Personalmente me gusta lo simple:

function sleep(seconds){
    var waitUntil = new Date().getTime() + seconds*1000;
    while(new Date().getTime() < waitUntil) 
        true;
}

luego:

sleep(2); // Sleeps for 2 seconds

Lo estoy usando todo el tiempo para crear los tiempos de carga falsos, mientras que la creación de secuencias de comandos en p5.js .

6
  • 3
    Veo esto como la versión más optimizada de la pregunta principal: no hace ninguna matemática dentro del ciclo, solo una simple comparación. Aunque es un poco difícil de leer.
    hegez
    27 oct 2017 a las 16:45
  • 9
    NUNCA HAGAS ESO. ¿Ha verificado el uso de la CPU mientras esta función está funcionando? Debería estar cerca del 100% si le da suficiente tiempo.
    eaorak
    18 dic 2017 a las 10:46
  • 3
    @hegez: Dado que el bucle se ejecutará durante una cantidad fija de tiempo de reloj de pared, pase lo que pase, parece que optimizar el bucle no viene al caso. 14/12/18 a las 1:27
  • @noego ¿Cómo es eso? Acabo de probar en el Nodo 10, no tengo ningún cambio en el uso de la CPU
    melMass
    11 mar.20 a las 16:21
  • 4
    @melMass Esta función simplemente bloquea el hilo del nodo durante n segundos manteniendo la CPU 100% ocupada. Esta "solución" es una idea extremadamente mala por esas dos razones (bloqueo + asesino de CPU). La espera TIENE que ser no bloqueante, por lo tanto asincrónica. 22 de mayo de 2020 a las 9:22
19

Una mejor solución para hacer que las cosas se vean como la mayoría de la gente quiere es usar una función anónima:

alert('start');
var a = 'foo';
// Lots of code
setTimeout(function(){  // Beginning of code that should run AFTER the timeout
    alert(a);
    // Lots more code
}, 5000);  // Put the timeout here

Esto es probablemente lo más cerca que estará de algo que simplemente hace lo que quiere.

Tenga en cuenta que si necesita varias horas de sueño, esto puede volverse feo rápidamente y es posible que deba reconsiderar su diseño.

1
  • este es el que me funcionó en los navegadores de escritorio y en un teléfono móvil más antiguo. Los otros que probé no funcionaron en todos.
    Mike
    21 de enero de 2020 a las 4:32
16

Actualización de 2019 con Atomics.wait

Debería funcionar en Node.js 9.3 o superior.

Necesitaba un temporizador bastante preciso en Node.js y funciona muy bien para eso.

Sin embargo, parece que la compatibilidad con los navegadores es extremadamente limitada.

let ms = 10000;
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);

Ejecuté algunos puntos de referencia del temporizador de 10 segundos.

Con setTimeout obtengo un error de hasta 7000 microsegundos (7 ms).

Con Atomics, mi error parece permanecer por debajo de 600 microsegundos (0,6 ms)

Actualización 2020: en resumen

function sleep(millis){ // Need help of a server-side page
  let netMillis = Math.max(millis-5, 0); // Assuming 5 ms overhead
  let xhr = new XMLHttpRequest();
  xhr.open('GET', '/sleep.jsp?millis=' + netMillis + '&rand=' + Math.random(), false);
  try{
    xhr.send();
  }catch(e){
  }
}

function sleepAsync(millis){ // Use only in async function
  let netMillis = Math.max(millis-1, 0); // Assuming 1 ms overhead
  return new Promise((resolve) => {
    setTimeout(resolve, netMillis);
  });
}
function sleepSync(millis){ // Use only in worker thread, currently Chrome-only
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, millis);
}

function sleepTest(){
  console.time('sleep');
  sleep(1000);
  console.timeEnd('sleep');
}

async function sleepAsyncTest(){
  console.time('sleepAsync');
  await sleepAsync(1000);
  console.timeEnd('sleepAsync');
}

function sleepSyncTest(){
  let source = `${sleepSync.toString()}
    console.time('sleepSync');
    sleepSync(1000);
    console.timeEnd('sleepSync');`;
  let src = 'data:text/javascript,' + encodeURIComponent(source);
  console.log(src);
  var worker = new Worker(src);
}

de los cuales la página del lado del servidor, por ejemplo sleep.jsp, se ve así:

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>
5
  • En mi opinión, es mejor que la solución aceptada que no se puede implementar como una función simple sin async / await en la persona que llama. 4 de agosto de 2019 a las 10:28
  • 2
    sí, siempre que sepa que esto es un bloqueo y que, por lo general, no es bueno 6 de agosto de 2019 a las 8:43
  • 1
    Bastante bueno, pero el hecho de que esto solo sea realmente compatible con Chrome y Firefox no lo hace muy viable para usos en la web. (Noviembre de 2019) 8/11/19 a las 12:14
  • ¡Esta era la respuesta que estaba buscando! No tuve acceso a las funciones asíncronas: D
    vitiral
    7 de febrero a las 20:45
  • En la rara situación en la que el bloqueo es deseable, esta es la solución correcta. ¡Ojalá hubiera visto tu respuesta antes de escribir en un blog sobre esto pensando que había encontrado una solución novedosa! En cualquier caso, para una explicación detallada, demostraciones y una variante adicional de la solución XHR que usa Service Worker: jasonformat.com/javascript-sleep 25 feb a las 22:54
13

La solución más corta sin dependencias:

await new Promise(resolve => setTimeout(resolve, 5000));
4
  • No funciona en IE11. Obtenemos un error de sintaxis para la función de flecha.
    DDphp
    22/01/20 a las 7:48
  • @ Uso de Java-DK await new Promise(function(resolve) { setTimeout(resolve, 5000); });
    k06a
    22/01/20 a las 11:43
  • Esta es idéntica a la respuesta de Ahmed Mohammedali (publicada primero). 6 de julio a las 23:26
  • @PeterMortensen y se copió de mi respuesta diferente que di en marzo de 2018: stackoverflow.com/a/49139664/440168
    k06a
    14 de julio a las 9:42
12

La mayoría de las respuestas aquí están equivocadas o al menos están desactualizadas. No hay ninguna razón por la que JavaScript deba ser de un solo subproceso y, de hecho, no lo es. Hoy en día, todos los navegadores convencionales son compatibles con los trabajadores. Antes de que este fuera el caso, otros tiempos de ejecución de JavaScript como Rhino y Node.js admitían subprocesos múltiples.

"JavaScript es de un solo subproceso" no es una respuesta válida. Por ejemplo, ejecutar una función de suspensión dentro de un trabajador no bloquearía ninguno de los códigos que se ejecutan en el subproceso de la interfaz de usuario.

En tiempos de ejecución más nuevos que admiten generadores y rendimiento, se podría brindar una funcionalidad similar a la función de suspensión en un entorno de un solo subproceso:

// This is based on the latest ES6 drafts.
// JavaScript 1.7+ (SpiderMonkey/Firefox 2+) syntax is slightly different

// Run code you want to sleep here (omit star if using JavaScript 1.7)
function* main(){
    for (var i = 0; i < 10; i++) {
        // To sleep for 10 milliseconds 10 times in a row
        yield 10;
    }

    yield 5;
    console.log('I just slept 5 milliseconds!');
}

// Resume the given generator after ms milliseconds
function resume(ms, generator){
    setTimeout(function(){
        // Omit .value if using JavaScript 1.7
        var nextSleep = generator.next().value;
        resume(nextSleep, generator);
    }, ms);
}

// Initialize a generator and get first sleep for the recursive function
var
    generator = main(),
    firstSleep = generator.next().value;

// Initialize recursive resume function
resume(firstSleep, generator);

Esta imitación del sueño es diferente de una verdadera función de sueño, ya que no bloquea el hilo. Es simplemente azúcar además de la función setTimeout actual de JavaScript . Este tipo de funcionalidad se implementó en Task.js y debería funcionar hoy en Firefox.

2
  • Los trabajadores no están implementados en IE, al menos a través de la versión 10. Lo que actualmente representa una gran cantidad de usuarios.
    Beejor
    14/06/15 a las 20:44
  • Es cierto, e incluso entonces no es práctico implementar sleeputilizando varios trabajadores. Si usa Node.js, las funciones del generador ya están implementadas y se pueden usar como se describe. Los navegadores convencionales no todos han implementado generadores hasta la fecha. 4 de septiembre de 2015 a las 15:07
11

Para los navegadores, estoy de acuerdo en que setTimeout y setInterval son el camino a seguir.

Pero para el código del lado del servidor, puede requerir una función de bloqueo (por ejemplo, para que pueda tener una sincronización de subprocesos de manera efectiva).

Si está usando Node.js y Meteor , es posible que se haya encontrado con las limitaciones de usar setTimeout en una fibra. Aquí está el código para la suspensión del lado del servidor.

var Fiber = require('fibers');

function sleep(ms) {
    var fiber = Fiber.current;
    setTimeout(function() {
        fiber.run();
    }, ms);
    Fiber.yield();
}

Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

Ver: Node.js Fibers, Sleep

1
  • 1
    Server may require a blocking function... No veo con qué fuerza bloquear el único hilo de Node y hacer que todo el servidor no responda durante varios segundos sea una buena idea, pero lo que sea 22 de mayo de 2020 a las 9:31
11

Encapsularía setTimeOut en una Promesa para la coherencia del código con otras tareas asincrónicas: Demostración en Fiddle

function sleep(ms)
{
    return(new Promise(function(resolve, reject) {
        setTimeout(function() { resolve(); }, ms);
    }));
}

Se usa así:

sleep(2000).then(function() {
   // Do something
});

Es fácil recordar la sintaxis si está acostumbrado a usar Promesas.

1
  • 4
    ¿Por qué esto es mejor que simplemente usar setTimeout (function () {/ * hacer algo * /}, 2000) ;? 9 de marzo de 2016 a las 10:15
9

He buscado / buscado en Google bastantes páginas web en JavaScript dormir / esperar ... y no hay respuesta si quieres que JavaScript "EJECUTE, RETRASA, EJECUTE" ... lo que la mayoría de la gente obtuvo fue "EJECUTAR, EJECUTAR (inútil cosas), RUN "o" RUN, RUN + RUN retardado "...

Pensé: aquí hay una solución que funciona ... pero tienes que recortar tus códigos de ejecución ...: Sí, lo sé, esta es una refactorización más fácil de leer ... todavía ...

Ejemplo 1:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setInterval
var i = 0;

function run() {
    // Pieces of codes to run
    if (i == 0){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i == 1){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i == 2){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i >2){document.getElementById("id1").innerHTML= "<p>code segment " + i + " is ran</p>"; }
    if (i == 5){document.getElementById("id1").innerHTML= "<p>all code segment finished running</p>"; clearInterval(t); } // End interval, stops run
    i++; // Segment of code finished running, next...
}

run();
t = setInterval("run()", 1000);

</script>
</body>
</html>

Ejemplo 2:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setTimeout
var i = 0;

function run() {
    // Pieces of codes to run, can use switch statement
    if (i == 0){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>"; sleep(1000);}
    if (i == 1){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>"; sleep(2000);}
    if (i == 2){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>"; sleep(3000);}
    if (i == 3){document.getElementById("id1").innerHTML= "<p>code segment " + i + " ran</p>";} //stops automatically
    i++;
}

function sleep(dur) {t=setTimeout("run()", dur);} // Starts flow control again after 'dur'

run(); // Starts
</script>
</body>
</html>

Ejemplo 3:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setTimeout
var i = 0;

function flow() {
    run(i);
    i++; // Code segment finished running, increment i; can put elsewhere
    sleep(1000);
    if (i == 5) {clearTimeout(t);} // Stops flow, must be after sleep()
}

function run(segment) {
    // Pieces of codes to run, can use switch statement
    if (segment == 0){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 1){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 2){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
}

function sleep(dur) {t=setTimeout("flow()", dur);} // Starts flow control again after 'dur'

flow(); // Starts flow
</script>
</body>
</html>

Ejemplo 4:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
// JavaScript sleep by "therealdealsince1982"; copyrighted 2009
// setTimeout, switch
var i = 0;

function flow() {
    switch(i)
    {
        case 0:
            run(i);
            sleep(1000);
            break;
        case 1:
            run(i);
            sleep(2000);
            break;
        case 5:
            run(i);
            clearTimeout(t); // Stops flow
            break;
        default:
            run(i);
            sleep(3000);
            break;
    }
}

function run(segment) {
    // Pieces of codes to run, can use switch statement
    if (segment == 0){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 1){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment == 2){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment " + segment + " is ran</p>"; }
    i++; // Current segment of code finished running, next...
}

function sleep(dur) {t=setTimeout("flow()", dur);} // Starts flow control again after 'dur'

flow(); // Starts flow control for first time...
</script>
</body>
</html>
1
  • 5
    Ok, esto funciona con setTimeput, pero es difícil ver qué está sucediendo. Usar setTimeout en sí es más fácil que esto.
    naugtur
    9 de agosto de 2011 a las 8:19
8

Puedo entender el propósito de una función de suspensión si tiene que lidiar con la ejecución sincrónica. Las funciones setInterval y setTimeout crean un subproceso de ejecución paralelo que devuelve la secuencia de ejecución al programa principal, lo cual no es efectivo si tiene que esperar un resultado dado. Por supuesto, se pueden usar eventos y controladores, pero en algunos casos no es lo que se pretende.

8
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}
3
  • 1
    Es lo mismo que la pregunta real. No tiene mucho sentido convertirla en la verdadera respuesta.
    EML
    12/06/2014 a las 19:16
  • 2
    No es una buena solución: usar esto en JavaScriptExecutor de Selenium cuelga mi navegador Chrome aproximadamente el 50% del tiempo en una MacBook Pro 2104.
    emery
    6 de mayo de 2015 a las 17:33
  • Una explicación estaría en orden. ¿Cuál es la idea / esencia? ¿En qué se diferencia de las respuestas anteriores? 6 de julio a las 16:36
8

Si desea funciones menos torpes que setTimeouty setInterval, puede envolverlas en funciones que simplemente invierten el orden de los argumentos y les dan buenos nombres:

function after(ms, fn){ setTimeout(fn, ms); }
function every(ms, fn){ setInterval(fn, ms); }

Versiones de CoffeeScript :

after = (ms, fn)-> setTimeout fn, ms
every = (ms, fn)-> setInterval fn, ms

Luego puede usarlos muy bien con funciones anónimas:

after(1000, function(){
    console.log("it's been a second");
    after(1000, function(){
        console.log("it's been another second");
    });
});

Ahora se lee fácilmente como "después de N milisegundos, ..." (o "cada N milisegundos, ...")

8

Desde Node.js 7.6 , puede combinar la promisifyfunción del módulo utils con setTimeout.

const sleep = require('util').promisify(setTimeout)

Uso general

async function main() {
    console.time("Slept for")
    await sleep(3000)
    console.timeEnd("Slept for")
}

main()

Uso de preguntas

async function asyncGenerator() {
    while (goOn) {
      var fileList = await listFiles(nextPageToken);
      await sleep(3000)
      var parents = await requestParents(fileList);
    }
  }
7

No puedes dormir así en JavaScript, o mejor dicho, no deberías. Ejecutar un ciclo de suspensión o while hará que el navegador del usuario se cuelgue hasta que finalice el ciclo.

Use un temporizador, como se especifica en el enlace al que hizo referencia.

7

Un escenario en el que podría querer una función sleep () en lugar de usar setTimeout () es si tiene una función que responde a un clic de usuario que finalmente terminará abriendo una nueva ventana emergente, por ejemplo, y ha iniciado algún procesamiento que requiere un período corto para completar antes de que se muestre la ventana emergente. Mover la ventana abierta a un cierre significa que normalmente el navegador la bloquea.

7

Se puede hacer usando el método de suspensión de Java. Lo probé en Firefox e Internet Explorer y no bloquea la computadora, no consume recursos ni causa interminables accesos al servidor. Me parece una solución limpia.

Primero tienes que cargar Java en la página y hacer que sus métodos estén disponibles. Para hacer eso, hice esto:

<html>
<head>

<script type="text/javascript">

  function load() {
    var appletRef = document.getElementById("app");
    window.java = appletRef.Packages.java;
  } // endfunction

</script>

<body onLoad="load()">

<embed id="app" code="java.applet.Applet" type="application/x-java-applet" MAYSCRIPT="true" width="0" height="0" />

Entonces, todo lo que tiene que hacer cuando desee una pausa indolora en su código JavaScript es:

java.lang.Thread.sleep(xxx)

Donde xxx es el tiempo en milisegundos. En mi caso (a modo de justificación), esto era parte del cumplimiento de pedidos de back-end en una empresa muy pequeña y necesitaba imprimir una factura que tenía que cargarse desde el servidor. Lo hice cargando la factura (como una página web) en un iFrame y luego imprimiendo el iFrame.

Por supuesto, tuve que esperar hasta que la página estuviera completamente cargada antes de poder imprimir, por lo que el código JavaScript tuvo que pausarse. Logré esto haciendo que la página de la factura (en el iFrame) cambiara un campo de formulario oculto en la página principal con el evento onLoad. Y el código en la página principal para imprimir la factura se veía así (partes irrelevantes cortadas para mayor claridad):

var isReady = eval('document.batchForm.ready');
isReady.value = 0;

frames['rpc_frame'].location.href = url;

while (isReady.value == 0) {
  java.lang.Thread.sleep(250);
} // endwhile

window.frames['rpc_frame'].focus();
window.frames['rpc_frame'].print();

Entonces, el usuario presiona el botón, el script carga la página de la factura, espera, verifica cada cuarto de segundo para ver si la página de la factura ha terminado de cargarse y aparece el cuadro de diálogo de impresión para que el usuario la envíe a la impresora. QED.

2
  • 13
    Parece una alusión bastante monstruosa cuando se considera lo simple que el autor quería lograr.
    xaralis
    22/01/2013 a las 16:17
  • 3
    Esto depende de los applets de Java que están en desuso. 12 de mayo de 2016 a las 13:22
7

Si está en Node.js , puede echar un vistazo a las fibras : una extensión nativa de C para el nodo, una especie de simulación de subprocesos múltiples.

Le permite hacer un real sleepde una manera que bloquea la ejecución en una fibra, pero no bloquea el hilo principal y otras fibras.

Aquí hay un ejemplo recién sacado de su propio archivo Léame:

// sleep.js

var Fiber = require('fibers');

function sleep(ms) {
    var fiber = Fiber.current;
    setTimeout(function() {
        fiber.run();
    }, ms);
    Fiber.yield();
}

Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

- y los resultados son:

$ node sleep.js
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
6

Para el caso específico de querer espaciar un conjunto de llamadas ejecutadas por un bucle, puede usar algo como el código siguiente con prototype. Sin prototipo, puede sustituir la función de retardo por setTimeout.

function itemHandler(item)
{
    alert(item);
}

var itemSet = ['a','b','c'];

// Each call to itemHandler will execute
// 1 second apart
for(var i=0; i<itemSet.length; i++)
{
    var secondsUntilExecution = i;
    itemHandler.delay(secondsUntilExecution, item)
}
0