Como Ceder o Controle ao Thread Principal para Melhorar o INP

Use scheduler.yield() para dividir tarefas longas e manter suas páginas responsivas

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-04

Ceder o controle ao thread principal

Imagine um filme romântico. O cenário é um pequeno mercado francês no centro de uma pequena vila. As ruas estão cheias de casais bebendo café, comendo croissants e comprando flores. Agora imagine o que acontece quando apenas um comprador pode adquirir algo de um vendedor simultaneamente enquanto todos os outros precisam esperar sua vez. O padeiro fica sobrecarregado com pedidos, discussões surgem na florista e o passeio romântico se transforma em uma espera frustrante.

Bem... é mais ou menos isso que acontece em um site quando as coisas ficam muito ocupadas.

Última revisão por Arjen Karel em março de 2026

Por que ceder o controle importa para o INP

O thread principal de um navegador lida com todos os processos importantes: análise de HTML e CSS, execução de JavaScript, tratamento de eventos de entrada como cliques e rolagens, e renderização visual. Ele funciona em um modelo de thread único, o que significa que só pode executar uma tarefa por vez. Quando uma tarefa começa a ser executada, o navegador a executará até o final e não parará até que esteja concluída. Nenhuma outra tarefa é agendada até que a atual termine. Isso é chamado de bloqueio do thread principal.

O bloqueio do thread principal é a causa primária de pontuações ruins de Interaction to Next Paint (INP). Quando um visitante clica em um botão e seu JavaScript bloqueia o thread principal por 200ms, o navegador não consegue pintar uma resposta até que o script termine. A fase de processing time do INP mede exatamente esse atraso. De acordo com o Web Almanac 2025, o Total Blocking Time mediano em dispositivos móveis é de 1.916ms, um aumento de 58% em relação ao ano anterior. São quase 2 segundos em que o navegador não consegue responder à entrada do usuário.

Uma forma de corrigir isso é cedendo o controle ao thread principal. Ceder o controle é uma técnica em que tarefas longas são divididas em múltiplas tarefas menores para permitir que o navegador lide com trabalho mais importante (como responder à entrada do usuário) entre elas.

Tarefas longas e período de bloqueio: Quando uma tarefa leva mais de 50 milissegundos, ela é classificada como uma tarefa longa, e qualquer coisa além desse limiar de 50 milissegundos é conhecida como o "período de bloqueio" da tarefa. Dividir essas tarefas longas em partes menores permite que o navegador permaneça responsivo, mesmo ao lidar com operações computacionalmente intensivas.

Estratégias antigas de yielding

Antes da Prioritized Task Scheduling API existiam 4 formas de ceder o controle ao thread principal. Todas têm limitações.

  • setTimeout(): A estratégia mais comum. setTimeout() com um atraso de 0 adiciona a tarefa ao final da fila, permitindo que outras tarefas sejam executadas primeiro. O problema: as tarefas só podem ser empurradas para o final da fila, então outros scripts podem furar a fila antes do seu código ser retomado. Chamadas aninhadas de setTimeout() também impõem um atraso mínimo de 5ms após cinco rodadas.
  • requestAnimationFrame(): Enfileira uma função para ser executada antes do próximo repaint do navegador. Frequentemente combinada com setTimeout() para garantir que os callbacks sejam agendados após a próxima atualização de layout. Não foi projetada para yielding; foi projetada para trabalho de animação.
  • requestIdleCallback(): Mais adequada para tarefas não críticas e de baixa prioridade que podem ser executadas durante o tempo ocioso do navegador. A limitação: não há garantia de que as tarefas agendadas serão executadas prontamente (ou nunca) em um thread principal ocupado.
  • isInputPending(): Verifica se há entradas pendentes do usuário e cede o controle apenas se uma entrada for detectada. O Google não recomenda mais essa abordagem. Ela pode retornar falsos negativos e não leva em conta outro trabalho crítico de desempenho, como animações e atualizações de renderização.

scheduler.yield()

As limitações desses métodos têm sido uma preocupação para a equipe do Chrome, especialmente com muitos sites falhando no INP. Para resolver isso, eles criaram scheduler.yield(): uma nova API que permite aos desenvolvedores ceder o controle ao thread principal imediatamente sem reorganizar a ordem das tarefas ou adicionar complexidade.

scheduler.yield() foi lançado como estável no Chrome 129 (setembro de 2024) e agora é suportado por todos os principais navegadores, exceto o Safari.

Exemplo de código

Como o Safari ainda não suporta scheduler.yield(), use um fallback para setTimeout():

function yieldToMain() {
  if ('scheduler' in window && 'yield' in window.scheduler) {
    return window.scheduler.yield();
  }
  return new Promise((resolve) => {
    setTimeout(resolve, 0);
  });
}

A função yieldToMain() verifica se window.scheduler.yield existe. Se existir, usa a API nativa. Se não, o código recorre ao setTimeout(). Isso corresponde ao padrão recomendado pelo Google.

Para projetos que precisam da Prioritized Task Scheduling API completa (incluindo scheduler.postTask() e TaskController), o Google Chrome Labs mantém um polyfill oficial.

Exemplo real: aprimorando a busca com yieldToMain()

Veja como yieldToMain() pode melhorar a experiência de busca para seus usuários.

A função handleSearch() primeiro atualiza o conteúdo do botão para dar feedback imediato de que uma busca está em andamento, depois cede o controle para permitir que o navegador pinte essa atualização. Em seguida, fetchData() recupera os dados de busca e updateHTML(data) exibe os resultados. Outro yieldToMain() garante uma atualização rápida de layout. Finalmente, tarefas menos importantes são agendadas durante o tempo ocioso do navegador. Note que não cedi o controle antes de requestIdleCallback() já que ela só é executada quando o thread principal está ocioso de qualquer forma.

async function handleSearch() {
  /* quickly update the button content after submitting */
  updateButtonToPending();

  /* Yield to Main */
  await yieldToMain();

  /* fetch data and update html */
  const data = await fetchData();
  updateHTML(data);

  /* Yield to Main again */
  await yieldToMain();

  /* some functions should only run during browser idle time */
  requestIdleCallback(sendDataToAnalytics);
}

Para outro exemplo prático, veja como usar esse mesmo padrão de yield com pushes de dataLayer para evitar que scripts de analytics bloqueiem interações.

Por que scheduler.yield() é melhor

Diferente de setTimeout(), que adiciona tarefas adiadas ao final da fila de tarefas, scheduler.yield() pausa a execução e coloca a continuação no início da fila. Seu código é retomado assim que o trabalho de maior prioridade (como o tratamento de callbacks de entrada) for concluído. Esta é a diferença chave: você pode ceder o controle ao thread principal sem o risco de outros scripts furarem a fila antes do seu código ser retomado.

scheduler.yield() também foi projetado para funcionar com a Prioritized Task Scheduling API. Quando chamado dentro de um callback de scheduler.postTask(), scheduler.yield() herda o nível de prioridade da tarefa. Essa combinação oferece controle granular sobre como seu JavaScript é priorizado e quando ele cede o controle.

Suporte de navegadores

scheduler.yield() é suportado por 71,5% dos navegadores globalmente:

  • Chrome 129+ e Edge 129+: estável desde setembro de 2024
  • Firefox 142+: estável desde agosto de 2025
  • Safari: não suportado, sem cronograma anunciado

O fallback com setTimeout() na função yieldToMain() acima garante que seu código funcione em todos os navegadores. Os usuários do Safari obtêm o comportamento mais antigo onde as continuações vão para o final da fila, mas a página ainda cede o controle. À medida que o suporte dos navegadores cresce, mais usuários automaticamente obterão a retomada mais rápida.

Se o problema são scripts de terceiros bloqueando completamente o thread principal, diferir esses scripts é um primeiro passo melhor do que ceder o controle. O yielding ajuda quando seu próprio código precisa fazer muito trabalho, mas você quer que o navegador permaneça responsivo entre as partes.

Para verificar que o yielding está melhorando seu INP no campo, monitore suas páginas com Real User Monitoring. Ferramentas de laboratório como o Lighthouse medem o Total Blocking Time, mas apenas dados de campo mostram o INP real que seus visitantes experimentam.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

17 years of fixing PageSpeed.

I have optimized platforms for some of the largest publishers and e-commerce sites in Europe. I provide the strategy, the code, and the RUM verification. Usually in 1 to 2 sprints.

View Services
Como Ceder o Controle ao Thread Principal para Melhorar o INPCore Web Vitals Como Ceder o Controle ao Thread Principal para Melhorar o INP