Como fazer o yield para a thread principal e melhorar o INP
Use o scheduler.yield() para dividir tarefas longas e manter suas páginas responsivas

Yield para a 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 tomando 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 têm que esperar a sua vez. O padeiro fica sobrecarregado de pedidos, discussões começam na floricultura 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 o yielding é importante para o INP
A 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. Ela opera em um modelo de thread única, o que significa que só pode executar uma tarefa por vez. Quando uma tarefa começa a ser executada, o navegador a executará até a conclusão e não irá parar até que termine. Nenhuma outra tarefa é agendada até que a atual seja finalizada. Isso é chamado de bloqueio da thread principal.
Bloquear a thread principal é a principal causa de pontuações ruins de Interaction to Next Paint (INP). Quando um visitante clica em um botão e o seu JavaScript bloqueia a thread principal por 200ms, o navegador não consegue pintar uma resposta até que o script termine. A fase de tempo de processamento do INP mede exatamente esse atraso. De acordo com o Web Almanac de 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 maneira de corrigir isso é fazendo o yield para a thread principal. O yielding é uma técnica onde tarefas longas são divididas em múltiplas tarefas menores para permitir que o navegador lide com trabalhos mais importantes (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 limite de 50 milissegundos é conhecida como o "período de bloqueio" da tarefa. Dividir essas tarefas longas em pedaços 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, havia 4 maneiras de fazer o yield para a thread principal. Todas possuem limitações.
- setTimeout(): A estratégia mais comum. O
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 que seu código seja retomado. Chamadas aninhadas desetTimeout()também impõem um atraso mínimo de 5ms após cinco rodadas. - requestAnimationFrame(): Coloca uma função na fila para ser executada antes da próxima repintura 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 o yielding; foi projetada para trabalhos de animação. - requestIdleCallback(): Mais adequada para tarefas não críticas e de baixa prioridade que podem ser executadas durante o tempo de inatividade do navegador. A limitação: não há garantia de que as tarefas agendadas serão executadas prontamente (ou sequer serão executadas) em uma thread principal ocupada.
- isInputPending(): Verifica se há entradas de usuário pendentes e faz o yield apenas se uma entrada for detectada. O Google não recomenda mais esta abordagem. Pode retornar falsos negativos e não leva em conta outros trabalhos críticos para o 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 o scheduler.yield(): uma nova API que permite aos desenvolvedores fazer o yield para a thread principal imediatamente, sem reorganizar a ordem das tarefas ou adicionar complexidade.
O scheduler.yield() foi lançado de forma 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 o scheduler.yield(), use um fallback para o 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, ela usa a API nativa. Caso contrário, o código usa o fallback para 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 na vida real: aprimorando a pesquisa com yieldToMain()
Veja como o yieldToMain() pode melhorar a experiência de pesquisa para seus usuários.
A função handleSearch() primeiro atualiza o conteúdo do botão para dar um feedback imediato de que uma pesquisa está em andamento, e então faz o yield para permitir que o navegador pinte essa atualização. Em seguida, fetchData() recupera os dados da pesquisa e updateHTML(data) exibe os resultados. Outro yieldToMain() garante uma atualização rápida de layout. Por fim, tarefas menos importantes são agendadas durante o tempo de inatividade do navegador. Note que eu não fiz o yield antes de requestIdleCallback(), pois ele só é executado quando a thread principal já está ociosa 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 este mesmo padrão de yield com envios para a dataLayer para evitar que scripts de analytics bloqueiem interações.
Por que o scheduler.yield() é melhor
Ao contrário do setTimeout(), que adiciona tarefas adiadas ao final da fila de tarefas, o scheduler.yield() pausa a execução e coloca a continuação no início da fila. Seu código é retomado assim que um trabalho de maior prioridade (como o tratamento de callbacks de entrada) for concluído. Esta é a principal diferença: você pode fazer o yield para a thread principal sem o risco de outros scripts furarem a fila antes que seu código seja retomado.

O scheduler.yield() também foi projetado para funcionar com a Prioritized Task Scheduling API. Quando chamado dentro de um callback do scheduler.postTask(), o scheduler.yield() herda o nível de prioridade da tarefa. Essa combinação oferece um controle refinado sobre como seu JavaScript é priorizado e quando ele faz o yield.
Suporte de navegadores
O scheduler.yield() é suportado por 71,5% dos navegadores globalmente:
- Chrome 129+ e Edge 129+: estáveis desde setembro de 2024
- Firefox 142+: estável desde agosto de 2025
- Safari: não suportado, sem cronograma anunciado
O fallback do 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 faz o yield. À medida que o suporte dos navegadores cresce, mais usuários obterão automaticamente a retomada mais rápida.
Se o problema for scripts de terceiros bloqueando a thread principal inteiramente, adiar (defer) esses scripts é um primeiro passo melhor do que fazer o yielding. O yielding ajuda quando o seu próprio código precisa fazer muito trabalho, mas você deseja que o navegador permaneça responsivo entre os trechos de código.
Para verificar se o yielding está melhorando o seu INP em campo, monitore suas páginas com o 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 vivenciam.
Escrevo código, não relatório.
Entro no seu time por 1 ou 2 sprints. Monto o monitoramento e garanto que o time mantém as métricas no verde depois que eu saio.
Entra em contato
