JavaScript Timers

setTimeout()

Quando estiver escrevendo código JavaScript, você pode querer aplicar um delay na execução de uma função.

Esse é o trabalho da função setTimeout. Você especifica uma função de callback para ser executada mais tarde, e um valor em milisegundos especificando o quão mais tarde ela deve rodar:

setTimeout(() => {
// roda após 2 segundos
}, 2000)
setTimeout(() => {
// roda após 50 milisegundos
}, 50)

Essa sintaxe define uma nova função. Você pode chamar qualquer outra função que quiser, ou passar o nome de uma função existente, e definir os parâmetros:

const myFunction = (firstParam, secondParam) => {
// faz algo
}
// roda após 2 segundos
setTimeout(myFunction, 2000, firstParam, secondParam)

setTimeout retorna o código de identificação do timer. Geralmente esse código não é usado, mas você pode guardá-lo, e "limpar" o timer se você quiser desagendar a execução daquela função:

const id = setTimeout(() => {
// deve rodar daqui 2 segundos
}, 2000)
// mudei de ideia :v
clearTimeout(id)

Delay de zero

Se você espeficiar o delay do timeout como 0, a função de callback será executada assim que possível, mas só depois da execução das funções correntes:

setTimeout(() => {
console.log('depois ')
}, 0)
console.log(' antes ')

imprime antes depois.

Isso é especialmente útil para evitar bloqueio da CPU em tarefas intensas e deixar outras funções serem executadas enquanto são feitos cálculos pesados, enfileirando funções no fluxo.

Alguns browsers (IE e Edge) implementam um método chamado setImmediate() que tem a exata mesma funcionalidade, mas não é padronizado e indisponível em outros navegadores. Porém é um método padrão no Node.js.

setInterval()

setInterval é uma função similar ao setTimeout, mas com uma diferença: em vez de rodar a função de callback uma vez, ela será rodada pra sempre, a cada intervalo de tempo especificado (em milisegundos):

setInterval(() => {
// roda a cada 2 segundos
}, 2000)

A função abaixo roda a cada 2 segundos até que você a diga pra parar, usando clearInterval, passando o identificador retornado por aquele setInterval:

const id = setInterval(() => {
// roda a cada 2 segundos
}, 2000)
clearInterval(id)

É comum chamar o clearInterval dentro da função de callback do setInterval, para auto-determinar se ele deve rodar de novo ou parar. Por exemplo, esse código roda algo a não ser que o valor de App.somethingIWait seja arrived:

const interval = setInterval(() => {
if (App.somethingIWait === 'arrived') {
clearInterval(interval)
return
}
// caso contrário, executa o conteúdo restante
}, 100)

setTimeout recursivo

O setInterval inicia uma função a cada n milisegundos, sem levar em consideração quando uma função finalizou sua execução.

Se uma função gasta sempre o mesmo espaço de tempo, show de bola:

setInterval funcionando belezinha

Talvez a função gaste tempos diferentes de execução, dependendo das condições da internet por exemplo:

setInterval variando de duração

E talvez uma longa execução sobreponha a próxima:

setInterval sobrepondo execuções

Para evitar isso, você pode agendar um setTimout recursivo para ser chamado quando a função de callback finaliza:

const myFunction = () => {
// faz algo
setTimeout(myFunction, 1000)
}
setTimeout(myFunction, 1000)

Pra chegar nesse cenário:

setTimeout recursivo

setTimeout e setInterval estão disponívels no Node.js, através do módulo Timers.

O Node.js também disponibiliza o setImmediate(), que é o equivalente de usar setTimeout(() => {}, 0), normalmente utilizado para trabalhar com o Event Loop do Node.js.