Ejecutar script después de un retraso específico usando JavaScript

189

¿Existe algún método de JavaScript similar al jQuery delay()o wait()(para retrasar la ejecución de un script por un período de tiempo específico)?

Niyaz
fuente

Respuestas:

189

Hay lo siguiente:

setTimeout(function, milliseconds);

función que se puede pasar el tiempo después del cual se ejecutará la función.

Ver: Método de ventanasetTimeout() .

Abhinav
fuente
3
No es una expresión que se ejecuta, es una función. La respuesta de @Marius lo ilustra.
pedrofurla
117
Esto no es un retraso, es un tenedor. El retraso debería funcionar en el mismo hilo.
DragonLord
13
Esto ejecutará inmediatamente function_reference. Para "trabajar" (asincrónicamente) se debe indicar como: setTimeout (function () {MethodToCall ();}, 1000);
Bernoulli IT
66
Quiero señalar que estamos hablando de JavaScript; sacar "hilos" o que debería funcionar "sincrónicamente" puede ser cierto técnica y semánticamente, pero no encaja realmente en el contexto de JavaScript, teniendo en cuenta que realmente no hay forma de lograr un retraso con ninguno de esos métodos (usted no ' t cree "hilos" en JS como lo hace en otros idiomas). Además, esto no se ejecutará inmediatamente a function_referencemenos que lo incluya (). Es decir, function_referenceeso es una referencia; pasar function_reference()invocaría la función de inmediato.
Danny Bullis
237

Solo para agregar a lo que todos los demás han dicho sobre setTimeout: si desea llamar a una función con un parámetro en el futuro, debe configurar algunas llamadas a funciones anónimas.

Debe pasar la función como argumento para que se llame más tarde. En efecto, esto significa sin corchetes detrás del nombre. Lo siguiente llamará a la alerta de inmediato y mostrará 'Hola mundo':

var a = "world";
setTimeout(alert("Hello " + a), 2000);

Para solucionar esto, puede poner el nombre de una función (como lo ha hecho Flubba) o puede usar una función anónima. Si necesita pasar un parámetro, debe usar una función anónima.

var a = "world";
setTimeout(function(){alert("Hello " + a)}, 2000);
a = "Stack Overflow";

Pero si ejecuta ese código, notará que después de 2 segundos la ventana emergente dirá 'Hola desbordamiento de pila'. Esto se debe a que el valor de la variable a ha cambiado en esos dos segundos. Para que diga 'Hola mundo' después de dos segundos, debe usar el siguiente fragmento de código:

function callback(a){
    return function(){
        alert("Hello " + a);
    }
}
var a = "world";
setTimeout(callback(a), 2000);
a = "Stack Overflow";

Esperará 2 segundos y luego emergerá 'Hola mundo'.

Mario
fuente
37

Solo para expandir un poco ... Puede ejecutar código directamente en la setTimeoutllamada, pero como dice @patrick , normalmente asigna una función de devolución de llamada, como esta. El tiempo es milisegundos

setTimeout(func, 4000);
function func() {
    alert('Do stuff here');
}
Polsonby
fuente
27

Si realmente desea tener una función de bloqueo (síncrona) delay(por cualquier motivo), ¿por qué no hacer algo como esto?

<script type="text/javascript">
    function delay(ms) {
        var cur_d = new Date();
        var cur_ticks = cur_d.getTime();
        var ms_passed = 0;
        while(ms_passed < ms) {
            var d = new Date();  // Possible memory leak?
            var ticks = d.getTime();
            ms_passed = ticks - cur_ticks;
            // d = null;  // Prevent memory leak?
        }
    }

    alert("2 sec delay")
    delay(2000);
    alert("done ... 500 ms delay")
    delay(500);
    alert("done");
</script>
Mario Werner
fuente
2
La dificultad con esta solución es que utiliza activamente un procesador, lo que conduce a un mayor uso de energía y una disminución de los recursos disponibles para otros subprocesos / procesos (por ejemplo, otras pestañas, otros programas). La suspensión, por el contrario, suspende temporalmente el uso de un hilo de los recursos del sistema.
ramcdougal 01 de
1
mejor usar Date.now () en lugar de la nueva Date () y no pensar en pérdidas de memoria
WayFarer
1
Por supuesto, es un uso intensivo de la CPU, pero para pruebas rápidas y sucias funciona
Maris B.
Quiero una versión que no bloquee el hilo, para poder actualizar el DOM antes delayde responder (para responder a esta pregunta ). ¿Hay alguna manera de hacerlo?
Gui Imamura
3
Una rutina más compacta: función de retraso (ms) {var start_time = Date.now (); while (Date.now () - hora_inicio <ms); }
Duke
15

Debe usar setTimeout y pasarle una función de devolución de llamada. La razón por la que no puedes usar sleep en javascript es porque bloquearías que toda la página no hiciera nada mientras tanto. No es un buen plan. Usa el modelo de eventos de Javascript y mantente feliz. ¡No luches!

Patricio
fuente
2
Aún así sería útil para fines de prueba. Como retrasar el envío de un formulario durante unos segundos para evaluar los cambios de página antes de que se realice una nueva solicitud HTTP.
rushinge
1
@rushinge luego configura la devolución de llamada para enviar el formulario y deshabilita el envío predeterminado del formulario
Populus
1
Mala idea dejar un enlace como código ... ya que ahora no funciona.
Emmet Arries
1
O sabes, podría arreglarlo.
Patrick
14

También puede usar window.setInterval () para ejecutar código repetidamente a intervalos regulares.

rcoup
fuente
2
setInterval () no debería usarse en su lugar debería usar setTimeout
paul
9
setTimeout()lo hace una vez, lo setInterval()hace repetidamente. Si desea que su código se ejecute cada 5 segundos, setInterval()está hecho para el trabajo.
rcoup
11

Para agregar los comentarios anteriores, me gustaría decir lo siguiente:

La setTimeout()función en JavaScript no detiene la ejecución del script per se, sino que simplemente le dice al compilador que ejecute el código en algún momento en el futuro.

No hay una función que realmente pueda pausar la ejecución integrada en JavaScript. Sin embargo, puede escribir su propia función que haga algo así como un bucle incondicional hasta que se alcance el tiempo utilizando la Date()función y agregando el intervalo de tiempo que necesita.

narasi
fuente
11

Si solo necesita probar un retraso, puede usar esto:

function delay(ms) {
   ms += new Date().getTime();
   while (new Date() < ms){}
}

Y luego, si quieres retrasar 2 segundos, lo haces:

delay(2000);

Sin embargo, podría no ser el mejor para la producción. Más sobre eso en los comentarios

Christoffer
fuente
@ U2744 COPO DE NIEVE ¿Puedes intentar ser un poco más preciso en tu comentario
Christoffer
1
Bueno, es un circuito ocupado que agotará las baterías de las computadoras portátiles y otros dispositivos móviles, y probablemente también evite que la UI responda (o incluso se muestre).
Ry-
@ U2744SNOWFLAKE Tiene sentido. He actualizado la respuesta, para lo que utilicé esta función :)
Christoffer
2
Funciona lo suficientemente bien en desarrollo para una solución rápida y sucia (y temporal).
HumanInDisguise
5

¿Por qué no puedes poner el código detrás de una promesa? (escrito en la parte superior de mi cabeza)

new Promise(function(resolve, reject) {
  setTimeout(resolve, 2000);
}).then(function() {
  console.log('do whatever you wanted to hold off on');
});

Al Joslin
fuente
5

La respuesta simple es:

setTimeout(
    function () {
        x = 1;
    }, 1000);

La función anterior espera 1 segundo (1000 ms) y luego establece x en 1. Obviamente, este es un ejemplo; Puedes hacer lo que quieras dentro de la función anónima.

Luca
fuente
4

Me gustó mucho la explicación de Maurius (la respuesta más votada) con los tres métodos diferentes para llamar setTimeout.

En mi código, deseo navegar automáticamente a la página anterior al completar un evento de guardar AJAX. La finalización del evento guardar tiene una ligera animación en el CSS que indica que el guardado fue exitoso.

En mi código encontré una diferencia entre los dos primeros ejemplos:

setTimeout(window.history.back(), 3000);

Este no espera el tiempo de espera: se llama a back () casi de inmediato, sin importar el número que ingrese para el retraso.

Sin embargo, cambiando esto a:

setTimeout(function() {window.history.back()}, 3000);

Esto hace exactamente lo que esperaba.

Esto no es específico de la operación back (), sucede lo mismo con alert(). Básicamente con el alert()utilizado en el primer caso, se ignora el tiempo de retraso. Cuando descarto la ventana emergente, la animación para el CSS continúa.

Por lo tanto, recomendaría el segundo o tercer método que describe, incluso si está utilizando funciones integradas y no está utilizando argumentos.

Doug
fuente
1

Tenía algunos comandos ajax que quería ejecutar con un retraso en el medio. Aquí hay un ejemplo simple de una forma de hacerlo. Sin embargo, estoy preparado para ser destrozado por mi enfoque poco convencional. :)

//  Show current seconds and milliseconds
//  (I know there are other ways, I was aiming for minimal code
//  and fixed width.)
function secs()
{
    var s = Date.now() + ""; s = s.substr(s.length - 5);
  return s.substr(0, 2) + "." + s.substr(2);
}

//  Log we're loading
console.log("Loading: " + secs());

//  Create a list of commands to execute
var cmds = 
[
    function() { console.log("A: " + secs()); },
    function() { console.log("B: " + secs()); },
    function() { console.log("C: " + secs()); },
    function() { console.log("D: " + secs()); },
    function() { console.log("E: " + secs()); },
  function() { console.log("done: " + secs()); }
];

//  Run each command with a second delay in between
var ms = 1000;
cmds.forEach(function(cmd, i)
{
    setTimeout(cmd, ms * i);
});

// Log we've loaded (probably logged before first command)
console.log("Loaded: " + secs());

Puede copiar el bloque de código y pegarlo en una ventana de consola y ver algo como:

Loading: 03.077
Loaded: 03.078
A: 03.079
B: 04.075
C: 05.075
D: 06.075
E: 07.076
done: 08.076
JohnnyIV
fuente
1

La solución más simple para llamar a su función con retraso es:

function executeWithDelay(anotherFunction) {
    setTimeout(anotherFunction, delayInMilliseconds);
}
Jackkobec
fuente
0

función de retraso:

/**
 * delay or pause for some time
 * @param {number} t - time (ms)
 * @return {Promise<*>}
 */
const delay = async t => new Promise(resolve => setTimeout(resolve, t));

uso dentro de la asyncfunción:

await delay(1000);
Zuhair Taha
fuente
-1

Como dijo otro, setTimeout es su apuesta más segura.
Pero a veces no puede separar la lógica de una nueva función, entonces puede usar Date.now () para obtener milisegundos y hacer el retraso usted mismo ...

function delay(milisecondDelay) {
   milisecondDelay += Date.now();
   while(Date.now() < milisecondDelay){}
}

alert('Ill be back in 5 sec after you click OK....');
delay(5000);
alert('# Im back # date:' +new Date());

JavaSheriff
fuente