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


2339

¿Hay una mejor manera de diseñar un sleepJavaScript en 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.


44
Es al conjunto en el medio de un tiempo, si yo uso setTimeout al mismo tiempo que continuará procesando y hacer cola más setTimeouts que eventualmente se ejecutan al mismo tiempo y haciendo un poco de concurrencia entre ellos
FMSF

160
Esta es una solución horrible: va a estar masticando los ciclos de procesamiento sin hacer nada.
17 de 26

12
El único propósito de un sueño es sondear o esperar una devolución de llamada: setInterval y setTimeout hacen ambas cosas mejor que esto.
annakata

1
Probablemente pueda hacer lo que quiera con el estilo de paso de continuación en JavaScript. Echa un vistazo a este artículo.
Ognyan Dimitrov

Posible duplicado de la secuencia
Anónimo

Respuestas:


2566

Actualización 2017-2019

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 frase:

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

Tenga en cuenta que,

  1. awaitsolo se puede ejecutar en funciones con la asyncpalabra clave como prefijo , o en el nivel superior de su script en algunos entornos (por ejemplo, la consola Chrome DevTools o Runkit).
  2. awaitsolo pausa la asyncfunción actual

Dos nuevas características de JavaScript ayudaron a escribir esta función de "suspensión":

Compatibilidad

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


55
Grandes cosas aquí. Me pregunto, ¿cómo afecta esto o se relaciona con los navegadores modernos "activos" / "inactivos" después de que JS llama al modo "suspensión"? ¿Puede el navegador bloquear la suspensión como se esperaba para el JS general, para recordar más tarde cuando se vuelve "activo", o tiene un comportamiento diferente?
Andre Canilho

18
¿Cuál es el soporte actual del navegador para esto? No consideraría que las soluciones anteriores fueran "obsoletas" hasta que esta solución sea compatible con la gran mayoría de los navegadores, o al menos todos los comunes. Por el contrario, consideraría esta solución interesante pero inutilizable / poco práctica hasta que tenga un amplio apoyo.
Alvin Thompson

75
Esto no es "sueño real" y no responde la pregunta. La persona que preguntó hizo una clara distinción entre stackoverflow.com/questions/758688/sleep-in-javascript y su pregunta. En reposo real, no se puede ejecutar ningún otro código (a menos que en otro hilo). Esta respuesta es buena para la otra pregunta.
niry

44
@jacroe: el transpilador maneja las funciones de flecha y asíncrono / espera (lo que haría que IE vomitara sangre de todos modos)
Jaromanda X

11
@niry JavaScript, al ser un lenguaje de subproceso único, no es adecuado para el sueño "real", ya que se ejecuta en el mismo subproceso que la interfaz de usuario y causaría páginas web que no responden.
Patrick Roberts el

849

(Ver la respuesta actualizada para 2016 )

Creo que es perfectamente razonable querer realizar una acción, esperar y luego realizar otra acción. Si estás acostumbrado a escribir en lenguajes multiproceso, probablemente tengas la idea de ejecutar durante un período de tiempo determinado hasta que tu hilo 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. ¿Y si quisiera utilizar 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, guárdelo en algún lugar, luego tráigalo de nuevo y continúe más tarde, luego podría pasar el sueño, pero eso sería básicamente un subproceso.

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

Su pregunta es un poco falsa, entonces. No hay forma de dormir de la manera que desea, ni debe buscar la solución que sugiere.


45
Esta no es una respuesta correcta en absoluto. Si Javascript no tiene una función de suspensión, es solo porque ECMAScript no lo 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 de tiempo determinada antes de ejecutar la siguiente línea de código, pero se eligió no hacerlo.
Didier A.

55
Un sueño puede implementarse perfectamente en JavaScript, aunque 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 se pueda hacer lo mismo cuando se emite un sleep () después de lo cual se devuelve el control 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 arruinaste el diseño tan mal que TÚ no tienes otra salida además de refactorizar completamente para lo que no tienes tiempo
Lawrence

Prueba Hypnotic, que sigue esta idea: coolwanglu.github.io/hypnotic/web/demo.html
Tezcat

44
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 una bifurcación () es trivialmente fácil, y aunque el rendimiento () no es realmente implementable, puede acercarse bastante usando memoria compartida para bloquear / semáforo. Para el programador promedio, tiene sentido tratarlo como multiproceso; El nombre técnico solo es importante para los desarrolladores del lenguaje.
Benubird

8
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 aún 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 bloquee la CPU y congele la aplicación como un loco. Es 2015 y no deberías poder bloquear un navegador web completo while(1). Tenemos Flash para cosas así.
Beejor

660

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

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

Editar

El sueño infame, o la función de retraso, en cualquier idioma es muy debatido. 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. Digo que cada uno de ellos tiene una regla y nunca puede dictar nada en esta industria.

Escribir una función de suspensión es simple y se hace 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!
});

190
A modo de cierre. function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); }
caos

68
ok, ¿y si el código no está destinado a ser usado en una página web?
Eugenio Miró

10
@ 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á dirigida al DOM que está expuesto a JavaScript que se ejecuta en las páginas web.
BrainSlugs83

31
@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 vuelvan a estar en un orden determinado. Tengo 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 las manos inactivas volverá al navegador y a cualquier otro subproceso que desee tiempo de CPU mientras todavía está bloqueando.
BrainSlugs83

382
Esta no es una respuesta a la pregunta.
TMS

303

Solo para depuración / desarrollo , publico esto si es útil para alguien

Cosas interesantes, en Firebug (y probablemente otras consolas js), no sucede nada después de presionar enter, solo después de la duración del sueño especificada (...)

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

Ejemplo de uso:

function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }

36
Esta no es una respuesta. Es exactamente el mismo que el código de la pregunta, excepto que es un poco más corto.
jab

16
Ocupado esperando, ¿en serio? En JS? Por segundos? Si encuentro un sitio web haciendo esto, será bloqueado.
mafu

35
@mafu Por eso se dice only for debug/dev... rolleyes
xDaizu

12
NUNCA HAGA ESTO. Esto hará que la CPU alcance el 100% en el núcleo que ejecuta y la bloqueará.
noego

3
Esto es útil, y quizás la ÚNICA forma de dormir, dentro de una aplicación de JavaScript de línea de comandos, porque async / await no es útil.
Wheezil

177

Estoy de acuerdo con los otros carteles, un sueño ocupado es solo 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 expire el tiempo de espera, por lo que no cumple la misma tarea que realizaría un sueño.

La forma de hacerlo es descomponer 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 hace cada pieza (IE GatherInputThenWait y CheckInput, en lugar de funcPart1 y funcPart2)

Editar

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

Editar más

Como se señaló en los comentarios, esto NO FUNCIONARÁ en un bucle. Podrías hacer un pirateo sofisticado (feo) para que funcione en un bucle, pero en general eso solo generará un código de espagueti desastroso.


12
Si. 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.
Nosredna

Touché Quiero decir, aún sería posible, pero feo y hack en ese caso. También podría usar algunas variables de estado booleano estáticas, pero eso también es bastante hack.
DevinB

2
-1 por esto. Nuevamente, esto no responde 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".
Deepak GM

66
@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 bajo el nombre indexcuando foo_continuefinalmente se llama.
Izkata

2
@Alexander Por supuesto que sí, porque el objetivo de setTimeout () es evitar que el navegador se bloquee ejecutando el código de forma astronómica. Ponga el console.log()interior foo_continue()en la versión setTimeout y obtendrá el mismo resultado.
Izkata

132

Por amor a $ DEITY, no realice una función de espera de ocupado. 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 por un segundo. Esto muestra cómo usar setInterval y setTimeout para mostrar y ocultar texto cada segundo.


3
Bueno, no todo: setInterval da una mejor impresión de sondeo.
annakata

3
¿Qué no retendría ese fragmento de código en el motor de JavaScript?
Deniz Dogan

10
A menos que necesite que el sueño sea sincrónico, en cuyo caso esta es una pregunta completamente válida.
Aaron Dufour

36
Creo que muchos de nosotros podríamos estar olvidando que JavaScript no es un lenguaje solo para navegadores. Este tipo podría estar creando una utilidad de línea de comando Node que requiere una breve pausa sin tener que lidiar con todos los problemas de alcance variable que vienen con setTimeout.
Phil LaNasa

3
@PhilLaNasa: Si el cierre sintáctico todavía está asustando a uno, uno realmente necesita abrocharse el cinturón y trabajar a través del Nodo 101.
caos

113

Sé que esta es una pregunta un poco antigua, pero si (como yo) estás usando Javascript con Rhino, puedes 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.
   */
}

44
¿Es esto una llamada a Java?
Ken Sharp

14
Esto es Java, no Javascript
RousseauAlexandre

18
@RousseauAlexandre Incorrecto. Es JavaScript usando Rhino (en ese momento, igualmente podría ser Nashorn en estos días)
mjaggard

71

Si está utilizando jQuery, alguien realmente creó un complemento de "retraso" 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');

44
Esa no es una mala solución. Mantiene el contexto y la viabilidad.
Nosredna

39
A partir de jQuery 1.4, .delay()es parte de jQuery (aunque con una semántica diferente de la implementación anterior). api.jquery.com/delay
Matt Ball

77
Lo que definitivamente le faltaba a esta pregunta era una respuesta de jQuery . ¡Me alegro de que lo hayamos conseguido!
xDaizu

1
Si necesita un retraso entre dos llamadas independientes, sí. Si necesita retrasos para reducir la velocidad de un bucle, no.
WGroleau

46

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

http://narayanraman.blogspot.com/2005/12/javascript-sleep-or-wait.html

... y aquí hay otro enlace con soluciones del lado del cliente: http://www.devcheater.com/

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. :)


35
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 pasar mucho tiempo haciendo una solución elegante.
user435779

31

Aquí hay una solución simple usando un XMLHttpRequest síncrono:

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

contenido de sleep.php:

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

Ahora llámalo con: sleep (5);


55
@lukad, use 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.
pguardiario

11
Enfoque único, aunque desafortunadamente XMLHttpRequests no asíncronos están en desuso y se eliminarán en el futuro. Lo cual es divertido, porque ese hecho es lo que me llevó a esta pregunta en primer lugar.
Beejor

Esta es realmente una muy buena idea de la OMI. Aunque no creo que la API de suspensión (URL de solicitud) deba ser pública, ya que se puede abusar de ella.
Vahid Amiri

@Beejor pensar siempre solo en el futuro significa vivir en una irrealidad futurista :-)
user1742529

bueno, pero ¿sabe si en algún momento Internet es lento o el tiempo de ping del sitio web es alto de lo que se suspenderá el script por más tiempo que el argumento? Por ejemplo, si usa un sleep(300)sitio web y tarda 150 ms en responder, el código de JavaScript se suspenderá durante 450 ms. y si el navegador pierde la conexión a Internet, solo funcionará durante 0 ms. Entonces no es una mejor solución
H Chauhan

30

Aqui 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) {}
}

17
Eso es básicamente lo mismo que tenía el OP.
Andrew Barber el

55
Para ser más precisos, es lo que OP solicitó una ALTERNATIVA.
WGroleau

La solución no es buena, pero async/awaitdesafortunadamente en algunos lugares no responde, y tenemos que usarla obligatoriamente.
Nabi KAZ

21

Personalmente me gusta lo simple:

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

entonces:

sleep(2); // Sleeps for 2 seconds

Lo estoy usando todo el tiempo para crear tiempo de carga falso mientras creo scripts en P5js


3
Veo esto como la versión más optimizada de la pregunta principal: no hace ninguna matemática dentro del ciclo, solo una comparación simple. Es un poco difícil de leer aunque.
hegez

44
NUNCA HAGAS ESO. ¿Ha verificado el uso de la CPU mientras esta función funciona? Debería estar cerca del 100% si le das suficiente tiempo.
noego

2
@hegez: Dado que el ciclo se ejecutará por una cantidad fija de tiempo de reloj de pared, pase lo que pase, parece que optimizar el ciclo no tiene importancia.
ShadowRanger

@noego ¿Cómo es eso? Acabo de probar en el Nodo 10, no tengo ningún cambio en el uso de la CPU
melMass

@melMass Esta función solo 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). Esperar tiene que ser sin bloqueo, por lo tanto, asíncrono.
Jeremy Thille

20

Primero:

Defina una función que desee ejecutar de esta manera:

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 paréntesis


18

Una mejor solución para hacer que las cosas se vean como lo que 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ás de algo que simplemente hace lo que quieres.

Tenga en cuenta que si necesita dormir varias veces, esto puede ponerse feo rápidamente y es posible que deba repensar su diseño.


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 absoluto.
Mike

10

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 efectiva).

Si está utilizando 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: https://github.com/laverdet/node-fibers#sleep


Server may require a blocking function... No veo cuán forzado es bloquear buena idea bloquear el único hilo de Node y hacer que todo su servidor no responda durante varios segundos, pero lo que sea
Jeremy Thille

10

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);        
    }));    
}

Usado así:

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

Es fácil recordar la sintaxis si solía usar Promesas.


44
¿Por qué es esto mejor que simplemente usar setTimeout (function () {/ * do something * /}, 2000) ;?
JSideris

10

Actualización de 2019 usando Atomics.wait

Debería funcionar en el Nodo 9.3 o superior.

Necesitaba un temporizador bastante preciso en Node.js y funciona muy bien para eso. Sin embargo, parece que hay un soporte extremadamente limitado en los navegadores.

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

Ejecuté algunos puntos de referencia de 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.6ms)

Actualización 2020: en resumen

function sleep(millis){ // need help of a server-side page
  let netMillis=Math.max(millis-5,0); //assuming 5ms 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 1ms 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 la cual se sleep.jspve una página del lado del servidor, por ejemplo ,

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>

En mi opinión, es mejor que la solución aceptada que no se puede implementar como una función simple sin async / wait en la persona que llama.
GroovyDotCom

Sí, siempre y cuando sepas que esto está bloqueando y que por lo general no es algo bueno
Kapytanhook

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. (Nov 2019)
JGreatorex

9

La mayoría de las respuestas aquí son erróneas o, como mínimo, desactualizadas. No hay ninguna razón por la que javascript tenga que ser de un solo subproceso, y de hecho no lo es. Hoy en día, todos los navegadores principales admiten a 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 tiene 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 ui.

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

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

// run code you want to sleep here (ommit star if using js 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(){
        // ommit .value if using js 1.7
        var nextSleep = generator.next().value;
        resume(nextSleep, generator);
    }, ms);
}

// initialize generator and get first sleep for 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 por encima de la función setTimeout actual de javascript. Este tipo de funcionalidad se ha implementado en Task.js y debería funcionar hoy en Firefox.


Los trabajadores no están implementados en IE, al menos hasta la versión 10. Que actualmente representa una gran cantidad de usuarios.
Beejor

Es cierto, y aun así no es práctico implementarlo sleepusando múltiples trabajadores. Si usa Node.js, las funciones del generador ya están implementadas y pueden usarse como se describe. Los navegadores convencionales no han implementado todos los generadores a partir de hoy.
Gabriel Ratener

8

He buscado / buscado en Google bastantes páginas web en JavaScript sleep / wait ... y NO hay respuesta si desea que JavaScript "EJECUTE, RETARDE, EJECUTE" ... lo que la mayoría de la gente recibió fue, "EJECUTAR, EJECUTAR (inútil cosas), RUN "o" RUN, RUN + RUN retrasado "....

Así que comí algunas hamburguesas y pensé ::: aquí hay una solución que funciona ... pero tienes que cortar 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>

// .................................... // ejemplo2:

<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>

// ................. ejemplo3:

<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>

// .............. ejemplo4:

<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>

55
Ok, esto funciona con setTimeput, pero es difícil ver qué está pasando. Usar setTimeout en sí es más fácil que esto.
naugtur

7
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

Es lo mismo que la pregunta real. No tiene mucho sentido que sea la respuesta real.
EML

2
No es una buena solución: usar esto en JavaScriptExecutor de Selenium bloquea mi navegador Chrome aproximadamente el 50% del tiempo en una MacBook Pro 2104.
esmeril

7

La solución más corta sin ninguna dependencia:

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

No funciona en IE11. Obtenemos un error de sintaxis para la función de flecha.
DDphp

@ Uso de Java-DKawait new Promise(function(resolve) { setTimeout(resolve, 5000); });
k06a

6

No puedes dormir así en JavaScript o, más bien, no deberías hacerlo. Ejecutar un ciclo de suspensión o tiempo hará que el navegador del usuario se bloquee hasta que finalice el ciclo.

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


6

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


6

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 en paralelo que devuelve la secuencia de ejecución al programa principal, lo que no es efectivo si tiene que esperar un resultado dado. Por supuesto, uno puede usar eventos y controladores, pero en algunos casos no es lo que se pretende.


6

Agregando mis dos bits. Necesitaba una espera ocupada para fines de prueba. No quería dividir el código, ya que sería mucho trabajo, así que lo hice por mí.

for (var i=0;i<1000000;i++){                    
     //waiting
  }

No veo ningún inconveniente en hacer esto y me sirvió.


Eso podría ser compilado.
Viktor Sehr

Por favor no lo hagas de esta manera. Esta es una llamada de bloqueo , lo que significa que no se puede ejecutar ningún otro javascript mientras su código está acaparando el hilo JS.
Steve Midgley

55
@SteveMidgley "ningún otro javascript [que pueda] ejecutarse mientras su código está acaparando el hilo JS" me parece exactamente lo que el OP quiere hacer ¯_ (ツ) _ / ¯
drigoangelo

1
Acabo de ejecutar algunas pruebas y parece que incluso un bucle vacío bloqueará el navegador y la CPU (no solo JavaScript). Y el uso de forbucles casi siempre se ejecutará de inmediato, independientemente del valor máximo para i, e incluso con el complejo código matemático colocado dentro. Entonces, a menos que solo esté esperando unos pocos milisegundos, todavía parece que no hay forma de dormir con gracia en JS.
Beejor

1 millón es demasiado grande. Para mí suficiente 10k
Vlad

6

Se puede hacer usando el método de suspensión de Java. Lo probé en FF e IE y no bloquea la computadora, no consume recursos ni causa interminables visitas al servidor. Parece una solución limpia para mí.

Primero debe 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 desea una pausa indolora en su JS 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 página web) en un iFrame y luego imprimiendo el iFrame. Por supuesto, tuve que esperar hasta que la página se haya cargado por completo antes de poder imprimir, por lo que el JS tuvo que hacer una pausa. Lo logré haciendo que la página de la factura (en el iFrame) cambie 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, luego espera, verificando cada cuarto de segundo para ver si la página de la factura ha terminado de cargarse, luego aparece el diálogo de impresión para que el usuario la envíe a la impresora. QED


12
Parece una alma monstruosa al considerar lo simple que el autor quería lograr.
xaralis

2
Esto depende de los Applets de Java que están en desuso.
Vahid Amiri

6

Muchas de las respuestas no responden (directamente) a la pregunta, y esta tampoco ...

Aquí están mis dos centavos (o funciones):

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

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 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, ...")


5

Para el caso específico de querer espaciar un conjunto de llamadas que se ejecutan mediante un bucle, puede usar algo como el siguiente código con prototipo. Sin prototipo, puede sustituir la función de retraso con 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)
}

5

Si estás en node.js, puedes echar un vistazo a las fibras : una extensión nativa de C para el nodo, una 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 reciente 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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.