Como ceder à thread principal

Ceda à thread principal para melhorar a responsividade da página

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-02-07

Ceder à 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 1 vendedor pode comprar 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 ...  isso é meio o que acontece em um site quando as coisas ficam muito ocupadas.

A importância de ceder

A thread principal de um navegador lida com todos os processos importantes e agenda todas as tarefas importantes (análise de HTML e CSS, execução de código JavaScript, tratamento de eventos de entrada como cliques e rolagens, e renderização visual ). 

A thread principal de um navegador é executada em um modelo de thread única. Isso significa que ela só pode executar uma tarefa de cada vez. Quando uma tarefa (geralmente execução de JavaScript ou renderização) começa a ser executada, o navegador executará essa tarefa 'até a conclusão' e não parará até que termine. Isso significa que ele não agendará nem executará nenhuma outra tarefa até que a tarefa anterior esteja pronta. Isso é chamado de 'bloquear a thread principal'. Bloquear a thread principal é um problema quando os visitantes interagem com uma página porque a página ficará irresponsiva durante o tempo de bloqueio . 

Uma maneira de corrigir o bloqueio da thread principal é 'Ceder à thread principal'. Ceder é uma técnica em que tarefas longas são divididas em várias tarefas menores  para permitir que a thread principal lide com tarefas mais importantes (como a entrada do usuário). 

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.

Antigas estratégias de ceder

Antes da nova API Prioritized Task Scheduling API havia 4 maneiras de ceder à thread principal. Todas têm as suas limitações e preocupações!

  • setTimeout(): A estratégia mais comum, setTimeout() funciona executando código em uma função de callback após um atraso especificado. Ao definir um atraso (ou tempo limite) de 0. setTimeout() adiciona a tarefa ao final da fila, permitindo que outras tarefas sejam executadas primeiro. Um grande problema é que, setTimeout() não é projetado para agendamento preciso porque as tarefas só podem ser empurradas para o final da fila.
  • requestAnimationFrame(): requestAnimationFrame() funciona enfileirando uma função para ser executada antes da próxima repintura do navegador. requestAnimationFrame() é frequentemente combinada com setTimeout() para garantir que as funções de callback sejam agendadas após a próxima atualização de layout.
  • requestIdleCallback(): Este método é mais adequado para tarefas não críticas e de baixa prioridade que podem ser executadas durante o tempo ocioso de um navegador. Embora ajude a manter a thread principal livre para tarefas mais cruciais, requestIdleCallback() sofre de uma limitação significativa: não há garantia de que as tarefas agendadas serão executadas prontamente (ou alguma vez!!!), especialmente em uma thread principal ocupada.
  • isInputPending(): isInputPending() funciona verificando entradas pendentes do usuário e cedendo apenas se uma entrada for detectada. isInputPending() pode ser usada em conjunto com outras funções de ceder para evitar ceder desnecessariamente. Infelizmente, ela pode retornar falsos negativos e não resolve a necessidade de ceder para outras tarefas críticas de desempenho, como animações.

Apresentando: scheduler.yield()

As limitações desses 4 métodos têm sido uma preocupação para a equipe do Chrome, especialmente com muitos sites falhando na métrica Interaction to Next Paint. Para corrigir isso e ajudar, a equipe do Chrome construiu novas APIs que oferecem controle granular sobre o agendamento de javascript.

Conheça o scheduler.yield()! Com window.scheduler.yield() os desenvolvedores podem ceder efetivamente à thread principal imediatamente sem reorganizar a ordem das tarefas ou criar complexidade extra.

Use o Scheduler.yield() de forma eficaz

Vamos mergulhar no código e explorar como aproveitar o scheduler.yield() da maneira que ele deve ser usado! Antes de começarmos a usar o scheduler.yield(), é importante verificar a compatibilidade do navegador porque é um recurso experimental e nem todos os navegadores o suportam ainda. 

Exemplo de código

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() é o núcleo do controle de ceder à thread principal. Ela primeiro verifica se tanto window.scheduler quanto window.scheduler.yield existem. Se existirem, podemos usar com segurança o window.scheduler.yield. Se  window.scheduler.yield não for suportado o código usa setTimeout como fallback).

Versão mais curta e pronta para produção

Ou use esta versão mais curta e pronta para produção que usa o operador ternário:

/* or shorter and production ready: */
function yieldToMain(){
  return"scheduler"in window&&"yield"in window.scheduler?
  window.scheduler.yield():new Promise(e=>{setTimeout(e,0)})
}

Exemplo da vida real: Aprimorando a Pesquisa com yieldToMain():

Vamos ver como podemos usar yieldToMain() para melhorar a experiência de pesquisa de seus usuários:

A função handleSearch() demonstra como yieldToMain() pode ser usado de forma eficaz. Ela primeiro atualiza o conteúdo do botão para fornecer feedback imediato de que uma pesquisa está em andamento. Você pode usar yieldToMain() aqui para permitir que o navegador atualize o layout.

Em seguida, fetchData() recupera dados de pesquisa e updateHTML(data) exibe os resultados. Outro  yieldToMain() garante uma rápida atualização de layout (já que nunca podemos ter certeza de que não há outros ouvintes de eventos esperando após essa tarefa).  Por fim, outras tarefas menos importantes são agendadas durante o tempo ocioso do navegador. Note que eu não cedi à thread principal aqui, já que requestIdleCallback() só será executado quando a thread principal estiver ociosa.

async function handleSeach(){
 /* 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 function should only run during browser idle time*/
 requestIdleCallback(sendDataToAnalytics);
}

Por que schedulier.yield() é simplesmente melhor

Ao contrário de setTimeout(), que adiciona tarefas adiadas ao final da fila de tarefas, scheduler.yield() apenas pausa a fila de javascript e as tarefas pausadas permanecem na frente da fila, garantindo que sejam executadas o mais rápido possível após tarefas de maior prioridade (como lidar com callbacks de entrada) terem sido concluídas. Esse comportamento de "frente da fila" resolve o maior problema dos métodos antigos de ceder . E os desenvolvedores agora podem 'ceder à thread principal' sem o risco de que suas tarefas importantes sejam atrasadas por outras tarefas menos importantes.

yielding timeline

Outra vantagem do scheduler.yield() é que ele foi projetado para funcionar com a API de Prioritized Task Scheduling como o scheduler.postTask(), que permite priorizar tarefas com base em sua importância. Esta combinação de recursos fornece aos desenvolvedores um poderoso kit de ferramentas para otimizar seus aplicativos da web para responsividade e desempenho.


Como ceder à thread principalCore Web Vitals Como ceder à thread principal