Como Ceder o Controle ao Thread Principal para Melhorar o INP
Use scheduler.yield() para dividir tarefas longas e manter suas páginas responsivas

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 desetTimeout()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.
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
