Menu

Sleep en TypeScript: cómo esperar o hacer un delay

TypeScript no tiene un sleep integrado, pero una línea te da uno: una función que devuelve una Promise<void> resuelta por setTimeout. Aprende a esperarla con await, pausar dentro de bucles, reintentar con un retardo, cancelar un sleep y por qué JavaScript no tiene un sleep bloqueante.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

TypeScript no tiene un sleep integrado. Escribe una función que devuelva una Promise<void> que setTimeout resuelve después del retardo, y luego espérala con await dentro de una función async:

await sleep(300) solo pausa main. El programa no se congela: los temporizadores, otras funciones async y la E/S siguen funcionando mientras espera.

Cómo funciona la función sleep

setTimeout(resolve, ms) programa la llamada a resolve al cabo de ms milisegundos, y llamar a resolve cumple la promesa. await sobre esa promesa suspende la función async hasta entonces.

El argumento de tipo <void> importa. Un new Promise(...) suelto no infiere su tipo a partir de las llamadas a resolve, así que sin él sleep devolvería Promise<unknown>. Y void es lo que permite llamar a resolve sin valor: en una Promise<number>, resolve() sin argumento es un error de compilación. Cuando la función tiene un tipo de retorno declarado, el argumento de tipo puede ir ahí:

setTimeout garantiza un mínimo, no un tiempo exacto: el callback se ejecuta cuando ha pasado el retardo y el event loop está libre. Cuenta con unos pocos milisegundos de margen.

Sleep dentro de un bucle

await sleep() dentro de un bucle for o for...of hace una pausa entre iteraciones, y así es como se regula el ritmo del trabajo (límites de peticiones, sondeos, animaciones en una terminal):

Esto no funciona dentro de forEach: ignora la promesa que devuelve cada callback async, así que todas las iteraciones empiezan a la vez y nada espera. Usa un bucle for o for...of, como se explica en la página de async/await.

Reintentar con un retardo

Un uso real habitual: intentar una operación y, si falla, esperar y volver a intentarlo, duplicando la espera cada vez (backoff exponencial).

El return await fn() dentro de try importa: sin await, se devolvería una promesa rechazada antes de que el catch pudiera verla.

Un sleep cancelable

Un sleep normal no se puede interrumpir. Para dejar de esperar antes (el usuario pulsó Cancelar, empezó un apagado), pasa un AbortSignal y limpia el temporizador cuando se dispare:

El programa termina justo después de la cancelación porque se limpió el temporizador largo. Sin clearTimeout, Node seguiría en marcha hasta que pasaran los 5 segundos.

Los temporizadores con promesas de Node

Node incluye una versión con promesas de setTimeout en el módulo node:timers/promises, así que en código de Node puedes importarla en lugar de escribir la función auxiliar. También acepta un valor con el que resolverse y un AbortSignal:

import { setTimeout as sleep } from "node:timers/promises";

async function main() {
    await sleep(1000);                              // wait one second
    const result = await sleep(500, "done");        // resolves with "done"
    const ac = new AbortController();
    await sleep(10_000, undefined, { signal: ac.signal }); // cancellable
}

Los tipos vienen de @types/node (npm i -D @types/node). Este módulo no existe en los navegadores, donde la función auxiliar de una línea es la opción portable.

No existe un sleep bloqueante

Los lenguajes con hilos tienen un sleep que bloquea el hilo actual. JavaScript ejecuta tu código en un único hilo con un event loop, así que un sleep bloqueante congelaría todo lo demás: no se dispararía ningún temporizador, no se atendería ninguna respuesta de red y, en un navegador, la página dejaría de responder. Un bucle activo que gira hasta que el reloj pasa de cierta hora hace exactamente eso, y nunca es la herramienta correcta.

El sleep asíncrono es cómo funciona la espera en JavaScript y TypeScript: la función se suspende, el hilo queda libre y la función se reanuda cuando se dispara el temporizador. Atomics.wait sí puede bloquear de verdad, pero solo sobre un SharedArrayBuffer, y los navegadores lo prohíben en el hilo principal; existe para coordinar hilos worker, no para hacer retardos.

Preguntas frecuentes

¿Cómo hago un sleep en TypeScript?

Define const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)); y llama a await sleep(1000) dentro de una función async. Pausa esa función durante un segundo aproximadamente sin bloquear el resto del programa.

¿Hay una función sleep integrada en TypeScript?

No. TypeScript añade tipos a JavaScript y no tiene una librería de ejecución propia, y JavaScript no tiene sleep. En Node puedes importar una: import { setTimeout as sleep } from "node:timers/promises". En el navegador, escribe la función auxiliar de una línea.

¿Por qué sleep necesita await?

sleep(1000) devuelve una promesa inmediatamente; solo await pausa la función async que la rodea hasta que se resuelve. Sin await, la línea siguiente se ejecuta enseguida. await solo funciona en una función async (o en el nivel superior de un ES module).

¿Puedo bloquear el hilo con un sleep síncrono en TypeScript?

No en código normal. JavaScript se ejecuta en un único hilo con un event loop, y un bucle de espera activa lo congela todo: los temporizadores, los callbacks de red, toda la página. Usa el sleep asíncrono. Atomics.wait puede bloquear un hilo en Node o en un worker, pero sirve para coordinar workers a bajo nivel, no para retardos.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR