16 pontos por GN⁺ 2025-09-22 | Ainda não há comentários. | Compartilhar no WhatsApp
  • Em JavaScript, setTimeout(0) na prática muitas vezes não executa imediatamente e acaba tendo um atraso mínimo de 4 ms, que é uma limitação padrão do navegador para evitar abusos
  • Essas restrições existem para impedir que sites abusem indiscriminadamente de timers e causem consumo de bateria ou queda na interatividade; no modo de economia de bateria o limite pode subir para 16 ms, e em abas em segundo plano pode chegar a 1 segundo
  • Para contornar as limitações do setTimeout, desenvolvedores vêm usando várias APIs alternativas de timer, como setImmediate, MessageChannel.postMessage, window.postMessage e scheduler.postTask
  • Em benchmarks reais, Chrome e Firefox aplicam o clamp de 4 ms, mas MessageChannel e scheduler.postTask funcionam quase sem atraso, enquanto o Safari se destaca por restringir setTimeout de forma mais agressiva
  • No fundo, trata-se de um equilíbrio entre proteger a experiência do usuário e preservar a liberdade dos desenvolvedores; hoje a Scheduler API vem se consolidando como solução padronizada, mas, se houver abuso, novos casos de intervenção do navegador (Intervention) ainda podem surgir

O contexto por trás das restrições do setTimeout

  • Mesmo com setTimeout(0), por causa de abuso, a execução real muitas vezes só acontece pelo menos 4 ms depois
    const start = performance.now()  
    setTimeout(() => {  
      // executa após cerca de 4 ms  
      console.log(performance.now() - start)  
    }, 0)  
    
  • O objetivo é impedir chamadas repetidas sem controle, reduzindo consumo de bateria e atrasos de renderização
  • Alguns navegadores reforçam ainda mais essas limitações dependendo do ambiente
    • Modo de bateria: 16 ms no Edge antigo
    • Aba em segundo plano: no Chrome, o atraso pode chegar a 1 segundo

O surgimento de outras APIs de timer

  • setImmediate: suportado apenas no IE e no Edge antigo, hoje praticamente descontinuado
  • MessageChannel.postMessage: envia trabalho ao event loop por um canal separado
  • window.postMessage: tem bom desempenho, mas há risco de conflito com outros scripts
  • scheduler.postTask: suportado por navegadores modernos e considerado a opção mais estável

Resultados de benchmark (MacBook Pro 2021, 101 repetições)

  • Chrome 139: setTimeout 4.2ms, scheduler.postTask 0ms
  • Firefox 142: setTimeout 4.72ms, scheduler.postTask 0.01ms
  • Safari 18.4: setTimeout 26.73ms, MessageChannel 0.52ms, window.postMessage 0.05ms

Caso do fake-indexeddb

  • O IndexedDB quer fazer commit automático da transação logo após o término das microtasks do event loop
  • No Node.js, setImmediate é ideal, mas no navegador setTimeout é ineficiente
  • Um trabalho que leva 300 ms no Chrome chegou a se estender até 4,8 segundos no navegador
  • Como solução, passou-se a usar scheduler.postTask por padrão e, por compatibilidade, MessageChannel/window.postMessage como fallback

A controvérsia sobre intervenção do navegador

  • Um lado argumenta que timers precisam ser limitados para que os desenvolvedores sejam protegidos de si mesmos
  • O outro lado defende que é preciso garantir liberdade para que os desenvolvedores possam medir e otimizar por conta própria
  • No fim, seguindo o princípio de priorizar o usuário, os navegadores intervêm para evitar abusos
  • A Scheduler API tenta conciliar as duas posições, oferecendo controle fino de tarefas aos desenvolvedores enquanto se alinha ao pipeline de renderização do navegador

Perspectivas futuras

  • postTask e postMessage devem continuar sem throttling por enquanto
  • Mas, se prioridades altas como user-blocking forem usadas em excesso, novas intervenções podem voltar a acontecer
  • No longo prazo, talvez seja necessário até mesmo outra API alternativa, como uma hipotética scheduler2

Ainda não há comentários.

Ainda não há comentários.