W3docs

JavaScript setTimeout e setInterval

Aprenda a agendar código em JavaScript com setTimeout e setInterval: sintaxe, argumentos, cancelamento de timers, setTimeout recursivo, comportamento de atraso zero, debouncing e throttling.

Às vezes você não quer executar código agora — você quer executá-lo mais tarde, ou executá-lo repetidamente. As duas funções de agendamento do JavaScript, setTimeout() e setInterval(), permitem exatamente isso. Este guia abrange a sintaxe delas, como passar argumentos, como cancelar um timer agendado, o importante padrão de "setTimeout recursivo", o comportamento surpreendente de um atraso zero e dois usos práticos: debouncing e throttling.

Nenhuma das funções faz parte da linguagem JavaScript principal — elas são fornecidas pelo ambiente host (navegadores e Node.js). O comportamento descrito aqui é o mesmo em ambos, com algumas diferenças observadas ao longo do caminho.

Introdução às Funções de Temporização do JavaScript

Um timer agenda um callback para ser executado após o código atual terminar e uma determinada quantidade de tempo ter passado. Como o JavaScript é single-threaded, o callback nunca interrompe o código em execução; ele aguarda em uma fila e só é executado quando a pilha de chamadas está vazia. (Para o mecanismo completo, veja The Event Loop.)

A Função setTimeout()

setTimeout() executa uma função uma vez após um atraso especificado. Ela aceita uma função para executar e um atraso em milissegundos antes dessa execução.

Sintaxe

let timerId = setTimeout(func, delay, arg1, arg2, ...);
  • func — a função (ou, menos comumente, uma string de código) a ser executada.
  • delay — o tempo de espera em milissegundos antes da execução. O padrão é 0.
  • arg1, arg2, ... — argumentos opcionais passados diretamente para func.

O valor de retorno é um id numérico de timer que você pode passar posteriormente para clearTimeout().

Exemplo

javascript— editable

Passando argumentos para o callback

Tudo que você colocar após o atraso é encaminhado para o callback. Isso é mais limpo do que envolver a chamada em outra arrow function:

javascript— editable
Aviso
Passe a própria função, não seu resultado. setTimeout(greet(), 1000) executa greet() imediatamente e agenda seu valor de retorno (provavelmente undefined). Escreva setTimeout(greet, 1000) — sem parênteses.

A Função setInterval()

setInterval() tem a mesma assinatura que setTimeout(), mas em vez de executar o callback uma vez, ela o executa repetidamente a cada delay milissegundos até você pará-la.

Sintaxe

let timerId = setInterval(func, delay, arg1, arg2, ...);

Exemplo

javascript— editable
Informação
Se o callback demorar mais para ser executado do que o intervalo, as chamadas podem se acumular e o espaçamento real se desviar. O navegador também garante um intervalo mínimo entre callbacks, portanto execuções consecutivas podem ser mais próximas do próximo tick do que o esperado. Quando o espaçamento preciso importa, prefira o padrão setTimeout recursivo abaixo.

setTimeout Recursivo vs. setInterval

Você pode reproduzir o comportamento de setInterval() fazendo com que um callback de setTimeout() se reagende. A diferença principal: setInterval() mede o atraso entre os inícios, enquanto o setTimeout() recursivo o mede entre o fim de uma execução e o início da próxima — garantindo uma pausa fixa mesmo quando o callback é lento.

javascript— editable

Cancelando Execução Agendada

Ambas as funções retornam um id de timer. Guarde esse id e você poderá cancelar o trabalho agendado com clearTimeout() ou clearInterval(). (As duas funções de cancelamento são na verdade intercambiáveis na maioria dos motores, mas combiná-las com o agendador que criou o id torna o código mais legível.)

Parando o setTimeout()

Para cancelar um timeout, armazene o id retornado por setTimeout() e passe-o para clearTimeout() antes de o atraso expirar.

Exemplo

javascript— editable

Parando o setInterval()

Da mesma forma, salve o id de setInterval() e passe-o para clearInterval(). Sem isso, o intervalo é executado indefinidamente (ou até a página ser fechada), o que é uma fonte comum de vazamentos de memória e timers descontrolados.

Exemplo

javascript— editable

O setTimeout de atraso zero

setTimeout(func, 0) não executa func imediatamente. Ele agenda func para ser executado assim que o código síncrono atual terminar. Esta é uma forma prática de "ceder" — permitir que o navegador repinte ou dividir uma tarefa longa em partes — e explica a ordem de saída que frequentemente surpreende iniciantes:

javascript— editable

Note que os timers são macrotasks: eles são executados após todas as microtasks enfileiradas (como callbacks de promessas resolvidas). Veja Event loop: microtasks and macrotasks para as regras de ordenação precisas.

Aplicações Práticas e Dicas

Dois dos usos práticos mais comuns de setTimeout() são debouncing e throttling — ambos são formas de limitar a frequência com que uma função é executada em resposta a eventos rápidos e sucessivos.

Debouncing com setTimeout()

Debouncing aguarda até que uma rajada de eventos tenha parado antes de executar a função. Cada novo evento redefine o timer, então o callback só dispara após as coisas ficarem quietas por wait milissegundos. Isso é ideal para uma caixa de pesquisa: você quer enviar uma requisição depois que o usuário parar de digitar, não uma por tecla pressionada.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Debounced Input Example</title>
<script>
    // Debounce function to limit the rate at which a function is executed
    function debounce(func, wait) {
        let timeout;

        return function executedFunction(...args) {
            const later = () => {
                clearTimeout(timeout);
                func(...args);
            };

            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    }

    // Function to be debounced
    function fetchData(input) {
        alert(`API call with input: ${input}`); // Placeholder for an API call
    }

    // Create a debounced version of fetchData
    const debouncedFetchData = debounce(fetchData, 300);

    // Add the debounced function to an event listener
    function setup() {
        document.getElementById('searchInput').addEventListener('input', (event) => {
            debouncedFetchData(event.target.value);
        });
    }

    // Ensure setup is called once the document is fully loaded
    document.addEventListener('DOMContentLoaded', setup);
</script>
</head>
<body>
    <h3>Type in the input field:</h3>
    <input type="text" id="searchInput" placeholder="Start typing..." />
</body>
</html>

Throttling com setTimeout()

Throttling executa a função no máximo uma vez por limit milissegundos, independentemente de quantos eventos chegam no intervalo. Onde o debouncing aguarda silêncio, o throttling garante uma cadência constante — perfeito para handlers de scroll, resize ou mousemove que de outra forma disparariam dezenas de vezes por segundo. O exemplo abaixo usa uma abordagem de leading-edge (executa imediatamente no primeiro evento, depois aplica o intervalo):

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Throttled Scroll Event</title>
<style>
  /* Simple styling for demonstration */
  body, html {
    height: 200%; /* Make the page scrollable */
    margin: 0;
    padding: 0;
    font-family: Arial, sans-serif;
  }
  #log {
    position: fixed;
    top: 0;
    left: 0;
    background: white;
    border: 1px solid #ccc;
    padding: 10px;
    width: 300px;
  }
</style>
</head>
<body>
<div id="log">Scroll to see the effect...</div>
<script>
// Throttle function using setTimeout
function throttle(func, limit) {
  let lastFunc;
  let lastRan;
  return function() {
    const context = this;
    const args = arguments;
    if (!lastRan) {
      func.apply(context, args);
      lastRan = Date.now();
    } else {
      clearTimeout(lastFunc);
      lastFunc = setTimeout(function() {
        if ((Date.now() - lastRan) >= limit) {
          func.apply(context, args);
          lastRan = Date.now();
        }
      }, Math.max(0, limit - (Date.now() - lastRan)));
    }
  }
}

// Function to be throttled
function handleScroll() {
  const log = document.getElementById('log');
  log.textContent = `Scroll event triggered at: ${new Date().toLocaleTimeString()}`;
}

// Add event listener for scroll
window.addEventListener('scroll', throttle(handleScroll, 1000));
</script>
</body>
</html>

Armadilhas a lembrar

  • Atrasos são um mínimo, não uma garantia. Se a pilha de chamadas estiver ocupada ou o event loop congestionado, o callback aguarda. O número que você passa é o mais cedo que pode ser executado, não uma promessa.
  • Abas em segundo plano são limitadas. A maioria dos navegadores restringe timers em abas inativas para aproximadamente uma vez por segundo para economizar energia, então animações e polling ficam mais lentos quando a aba está oculta.
  • Timeouts aninhados são limitados a ~4ms. Após cinco chamadas aninhadas de setTimeout(), os navegadores impõem um atraso mínimo de cerca de 4 milissegundos, então um atraso 0 nunca é verdadeiramente zero em cadeias profundas.
  • Atraso máximo. Um atraso maior que 2147483647 (2^31 − 1) estoura o campo de 32 bits e é tratado como 0, disparando quase imediatamente em vez de no futuro distante.
  • Vinculação do this. Quando você passa um método como setTimeout(obj.method, 1000), ele perde seu this. Use uma arrow function — setTimeout(() => obj.method(), 1000) — ou obj.method.bind(obj).
  • Sempre faça limpeza. Cancele intervalos (e timeouts pendentes) quando um componente for desmontado ou o trabalho não for mais necessário, ou você vazará timers e poderá operar em estado obsoleto.

Tópicos relacionados

Conclusão

setTimeout() executa código uma vez após um atraso; setInterval() o executa em um cronograma repetido; clearTimeout() e clearInterval() os cancelam. Lembre-se de que os atrasos são mínimos, passe argumentos após o atraso em vez de dentro de um wrapper, recorra ao padrão de setTimeout recursivo quando precisar de espaçamento constante e sempre faça a limpeza dos timers que não são mais necessários. Com debouncing e throttling por cima, essas duas pequenas funções cobrem a maior parte do trabalho baseado em tempo que você fará no navegador.

Prática

Prática
Quais das afirmações a seguir são verdadeiras em relação ao uso de `setTimeout()` e `setInterval()` em JavaScript?
Quais das afirmações a seguir são verdadeiras em relação ao uso de `setTimeout()` e `setInterval()` em JavaScript?
Was this page helpful?