setTimeout()
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
El método global setTimeout()
establece un temporizador que ejecuta una función o una pieza de código específica una vez que expira el temporizador.
Sintaxis
setTimeout(code)
setTimeout(code, delay)
setTimeout(functionRef)
setTimeout(functionRef, delay)
setTimeout(functionRef, delay, param1)
setTimeout(functionRef, delay, param1, param2)
setTimeout(functionRef, delay, param1, param2, /* … ,*/ paramN)
Parámetros
functionRef
-
Una
función
que se ejecutará después de que expire el temporizador. code
-
Una sintaxis alternativa que le permite incluir una cadena en lugar de una función, que se compila y ejecuta cuando expira el temporizador. Esta sintaxis no se recomienda por las mismas razones que hacen que el uso de
eval()
sea un riesgo para la seguridad. delay
Opcional-
El tiempo, en milisegundos, que el temporizador debe esperar antes de que se ejecute la función o el código especificado. Si se omite este parámetro, se utiliza un valor de 0, lo que significa ejecutar "inmediatamente", o más exactamente, el siguiente ciclo de eventos.
Tenga en cuenta que, en cualquier caso, la demora real puede ser mayor de lo previsto; consulte Motivos de los retrasos superiores a los especificados a continuación.
También tenga en cuenta que si el valor no es un número, se realiza una coerción implícita silenciosamente en el valor para convertirlo en un número, lo que puede generar resultados inesperados y sorprendentes; consulte Los valores de retardo no numéricos se transforman silenciosamente en números para ver un ejemplo.
param1
, …,paramN
Opcional-
Argumentos adicionales que se pasan a través de la función especificada por
functionRef
.
Valor devuelto
El timeoutID
devuelto es un valor entero positivo que identifica el temporizador creado por la llamada a setTimeout()
. Este valor se puede pasar a clearTimeout()
para cancelar el tiempo de espera.
Se garantiza que un valor de timeoutID
nunca será reutilizado por una llamada posterior a setTimeout()
o setInterval()
en el mismo objeto (una ventana o un worker). Sin embargo, los diferentes objetos usan grupos separados de ID.
Descripción
Los tiempos de espera se cancelan usando clearTimeout()
.
Para llamar a una función repetidamente (por ejemplo, cada N milisegundos), considere usar setInterval()
.
Los valores de retardo no numéricos se convierten silenciosamente en números
Si se llama a setTimeout()
con un valor de delay que no es un número, una coerción implícita se realiza silenciosamente en el valor para convertirlo en un número. Por ejemplo, el siguiente código usa incorrectamente la cadena "1000"
para el valor delay, en lugar del número 1000
, pero aún así funciona, porque cuando se ejecuta el código, la cadena se convierte en el número 1000
. y así el código se ejecuta 1 segundo después.
setTimeout(() => {
console.log("Retrasado por 1 segundo.");
}, "1000");
Pero en muchos casos, la coerción de tipo implícito puede conducir a resultados inesperados y sorprendentes. Por ejemplo, cuando se ejecuta el siguiente código, la cadena "1 segundo"
finalmente se convierte en el número 0
y, por lo tanto, el código se ejecuta inmediatamente, sin demora.
setTimeout(() => {
console.log("Retrasado por 1 segundo.");
}, "1 segundo");
Por lo tanto, no use cadenas para el valor de delay, sino que use siempre números:
setTimeout(() => {
console.log("Retrasado por 1 segundo.");
}, 1000);
Trabajando con funciones asíncronas
setTimeout()
es una función asíncrona, lo que significa que la función del temporizador no pausará la ejecución de otras funciones en la pila de funciones.
En otras palabras, no puede usar setTimeout()
para crear una "pausa" antes de que se active la siguiente función en la pila de funciones.
Vea el siguiente ejemplo:
setTimeout(() => {
console.log("este es el primer mensaje");
}, 5000);
setTimeout(() => {
console.log("este es el segundo mensaje");
}, 3000);
setTimeout(() => {
console.log("este es el tercer mensaje");
}, 1000);
// Salida:
// este es el tercer mensaje
// este es el segundo mensaje
// este es el primer mensaje
Tenga en cuenta que la primera función no crea una "pausa" de 5 segundos antes de llamar a la segunda función. En su lugar, se llama a la primera función, pero espera 5 segundos para ejecutarse. Mientras la primera función está esperando para ejecutarse, se llama a la segunda función y se aplica una espera de 3 segundos a la segunda función antes de que se ejecute. Dado que ni los temporizadores de la primera ni la segunda función se han completado, se llama a la tercera función y completa su ejecución primero. Luego sigue el segundo. Luego, finalmente, la primera función se ejecuta después de que finalmente se completa su temporizador.
Para crear una progresión en la que una función solo se dispara después de la finalización de otra función, consulte la documentación de Promesas.
El problema de "this"
Cuando pasa un método a setTimeout()
, se invocará con un valor this
que puede diferir de sus expectativas. El tema general se explica detalladamente en la referencia de JavaScript.
El código ejecutado por setTimeout()
se llama desde un contexto de ejecución separado de la función desde la que se llamó a setTimeout
.
Se aplican las reglas habituales para configurar la palabra clave this
para la función llamada, y si no ha configurado this
en la llamada o con bind
, se establecerá por defecto en el objeto window
(o global
). No será lo mismo que el valor this
para la función que llamó a setTimeout
.
Vea el siguiente ejemplo:
const myArray = ["cero", "uno", "dos"];
myArray.myMethod = function (sProperty) {
console.log(arguments.length > 0 ? this[sProperty] : this);
};
myArray.myMethod(); // muestra "cero,uno,dos"
myArray.myMethod(1); // muestra "uno"
Lo anterior funciona porque cuando se llama a myMethod
, this
se establece en myArray
mediante la llamada, por lo que dentro de la función, this[sProperty]
es equivalente a myArray[sProperty]
. Sin embargo, en lo siguiente:
setTimeout(myArray.myMethod, 1.0 * 1000); // muestra "[object Window]" después de 1 segundo
setTimeout(myArray.myMethod, 1.5 * 1000, "1"); // muestra "undefined" después de 1.5 segundos
La función myArray.myMethod
se pasa a setTimeout
, luego, cuando se llama, this
no está configurado, por lo que se establece de manera predeterminada en el objeto window
.
Tampoco existe la opción de pasar un thisArg
a setTimeout
como ocurre en los métodos Array como forEach()
y reduce()
. Como se muestra a continuación, usar call
para configurar this
tampoco funciona.
setTimeout.call(myArray, myArray.myMethod, 2.0 * 1000); // error
setTimeout.call(myArray, myArray.myMethod, 2.5 * 1000, 2); // mismo error
Soluciones
Usar una función contenedora
Una forma común de resolver el problema es usar una función contenedora que establece this
en el valor requerido:
setTimeout(function () {
myArray.myMethod();
}, 2.0 * 1000); // muestra "cero,uno,dos" después de 2 segundos
setTimeout(function () {
myArray.myMethod("1");
}, 2.5 * 1000); // muestra "uno" después de 2.5 segundos
La función contenedora puede ser una función de flecha:
setTimeout(() => {
myArray.myMethod();
}, 2.0 * 1000); // muestra "cero,uno,dos" después de 2 segundos
setTimeout(() => {
myArray.myMethod("1");
}, 2.5 * 1000); // muestra "uno" después de 2.5 segundos
Usar bind()
Alternativamente, puede usar bind()
para establecer el valor de this
para todas las llamadas a una función determinada:
const myArray = ["cero", "uno", "dos"];
const myBoundMethod = function (sProperty) {
console.log(arguments.length > 0 ? this[sProperty] : this);
}.bind(myArray);
myBoundMethod(); // muestra "cero,uno,dos" ya que 'this' está vinculado a myArray en la función
myBoundMethod(1); // muestra "uno"
setTimeout(myBoundMethod, 1.0 * 1000); // sigue mostrando "cero,uno,dos" después de 1 segundo debido a que está vinculado
setTimeout(myBoundMethod, 1.5 * 1000, "1"); // muestra "uno" después de 1.5 segundos
Pasar cadenas
Pasar una cadena en lugar de una función a setTimeout()
tiene los mismos problemas que usar eval()
.
// No hacer esto
setTimeout("console.log('¡Hola mundo!');", 500);
// Hacer esto en su lugar
setTimeout(() => {
console.log("¡Hola mundo!");
}, 500);
Una cadena pasada a setTimeout()
se evalúa en el contexto global, por lo que los símbolos locales en el contexto donde se llamó a setTimeout()
no estarán disponibles cuando la cadena se evalúa como código.
Motivos de los retrasos superiores a los especificados
Hay una serie de razones por las que un tiempo de espera puede tardar más de lo previsto en activarse. Esta sección describe las razones más comunes.
Tiempos de espera anidados
Como se especifica en el estándar HTML, los navegadores impondrán un tiempo de espera mínimo de 4 milisegundos una vez que una llamada anidada a setTimeout
se ha programado 5 veces.
Esto se puede ver en el siguiente ejemplo, en el que anidamos una llamada a setTimeout
con un retraso de 0
milisegundos, y registramos el retraso cada vez que se llama al manejador. Las primeras cuatro veces, el retraso es de aproximadamente 0 milisegundos, y después de eso, es de aproximadamente 4 milisegundos:
<button id="run">Ejecutar</button>
<table>
<thead>
<tr>
<th>Anterior</th>
<th>Éste</th>
<th>Retraso actual</th>
</tr>
</thead>
<tbody id="log"></tbody>
</table>
let last = 0;
let iterations = 10;
function timeout() {
// registra la hora de esta llamada
logline(new Date().getMilliseconds());
// si no ha terminado, programa la próxima llamada
if (iterations-- > 0) {
setTimeout(timeout, 0);
}
}
function run() {
// borrar el registro
const log = document.querySelector("#log");
while (log.lastElementChild) {
log.removeChild(log.lastElementChild);
}
// inicializar el recuento de iteraciones y la marca de tiempo de inicio
iterations = 10;
last = new Date().getMilliseconds();
// temporizador de inicio
setTimeout(timeout, 0);
}
function logline(now) {
// registrar la última marca de tiempo, la nueva marca de tiempo y la diferencia
const tableBody = document.getElementById("log");
const logRow = tableBody.insertRow();
logRow.insertCell().textContent = last;
logRow.insertCell().textContent = now;
logRow.insertCell().textContent = now - last;
last = now;
}
document.querySelector("#run").addEventListener("click", run);
Tiempos de espera en pestañas inactivas
Para reducir la carga (y el uso de batería asociado) de las pestañas en segundo plano, los navegadores impondrán un tiempo de espera mínimo en las pestañas inactivas. También se puede renunciar si una página está reproduciendo sonido usando una API de audio web AudioContext
.
Los detalles de esto dependen del navegador:
- Firefox Desktop y Chrome tienen un tiempo de espera mínimo de 1 segundo para pestañas inactivas.
- Firefox para Android tiene un tiempo de espera mínimo de 15 minutos para las pestañas inactivas y puede limpiarla por completo.
- Firefox no acelera las pestañas inactivas si la pestaña contiene un
AudioContext
.
Limitación de scripts de seguimiento
Firefox impone una limitación adicional para las secuencias de comandos que reconoce como secuencias de comandos de seguimiento. Cuando se ejecuta en primer plano, el retraso mínimo de limitación sigue siendo de 4 ms. Sin embargo, en las pestañas en segundo plano, el retraso mínimo de limitación es de 10 000 ms, o 10 segundos, que entra en vigor 30 segundos después de que se haya cargado un documento por primera vez.
Consulte Protección de rastreo para obtener más detalles.
Tiempos de espera tardíos
El tiempo de espera también puede activarse más tarde de lo esperado si la página (o el sistema operativo/navegador) está ocupado con otras tareas.
Un caso importante a tener en cuenta es que la función o el fragmento de código no se puede ejecutar hasta que el hilo que llamó setTimeout()
haya terminado. Por ejemplo:
function foo() {
console.log("foo ha sido llamado");
}
setTimeout(foo, 0);
console.log("Después de setTimeout");
Escribirá en la consola:
Después de setTimeout foo ha sido llamado
Esto se debe a que, aunque se llamó a setTimeout
con un retraso de cero, se coloca en una cola y se programa para ejecutarse en la próxima oportunidad; no inmediatamente.
El código que se está ejecutando actualmente debe completarse antes de que se ejecuten las funciones en la cola, por lo que el orden de ejecución resultante puede no ser el esperado.
Aplazamiento de tiempos de espera durante la carga de la página
Firefox aplazará la activación de los temporizadores setTimeout()
mientras se carga la pestaña actual. La activación se difiere hasta que el subproceso principal se considera inactivo (similar a window.requestIdleCallback()), o hasta que se activa el evento de carga.
Temporizadores y páginas de WebExtension
En WebExtensions, setTimeout()
no funciona de forma fiable. Los autores de extensiones deben usar la API alarms
en su lugar.
Valor de retardo máximo
Los navegadores almacenan internamente el retraso como un entero con signo de 32 bits. Esto provoca un desbordamiento de enteros cuando se utilizan retrasos superiores a 2 147 483 647 ms (alrededor de 24,8 días), lo que hace que el tiempo de espera se ejecute inmediatamente.
Ejemplo
Configuración y borrado de tiempos de espera
El siguiente ejemplo configura dos botones simples en una página web y los vincula a las rutinas setTimeout()
y clearTimeout()
. Al presionar el primer botón, se establecerá un tiempo de espera que muestra un mensaje después de dos segundos y almacena la identificación del tiempo de espera para que la use clearTimeout()
. Opcionalmente, puede cancelar este tiempo de espera presionando el segundo botón.
HTML
<button onclick="delayedMessage();">
Mostrar un mensaje después de dos segundos
</button>
<button onclick="clearMessage();">Cancelar mensaje antes de que suceda</button>
<div id="output"></div>
JavaScript
let timeoutID;
function setOutput(outputContent) {
document.querySelector("#output").textContent = outputContent;
}
function delayedMessage() {
setOutput("");
timeoutID = setTimeout(setOutput, 2 * 1000, "¡Eso fue muy lento!");
}
function clearMessage() {
clearTimeout(timeoutID);
}
Resultado
Ver también el ejemplo clearTimeout()
.
Especificaciones
Specification |
---|
HTML Standard # dom-settimeout-dev |
Compatibilidad con navegadores
BCD tables only load in the browser