Talvez você já tenha visto a página congelar: o botão não responde, a animação para, o clique demora. Acontece quando um script pesado ocupa a thread principal do navegador. Os Web Workers existem para tirar esse peso das costas da interface. A ideia é simples: rodar código em segundo plano, sem bloquear o que o usuário vê. Neste guia, você vai seguir um passo a passo para aplicar isso com cautela, entendendo o que ganha e o que evita.
Passo 1: Entenda o que está travando
Antes de sair movendo código, identifique o gargalo. Abra o DevTools, aba Performance, grave alguns segundos de interação e observe long tasks. Se um trecho de JavaScript passa de 50 ms sem pausa, é candidato a virar worker. Cálculos matemáticos, parsing de arquivos grandes e processamento de imagens costumam se encaixar. Já manipulação direta do DOM não pode ir para o worker.
Erro comum: mover qualquer função para o worker sem medir. Isso adiciona complexidade sem ganho real.
Passo 2: Crie o arquivo do worker
Um worker é um script separado. Crie um arquivo, por exemplo worker.js, e instancie no código principal com new Worker('worker.js'). O worker não acessa window nem document. Ele tem o próprio escopo global, chamado self. Essa separação é o que garante o isolamento, mas também exige que você pense em como os dados vão e voltam.
Dica: mantenha o arquivo pequeno e com uma responsabilidade só. Worker que faz tudo vira uma caixa-preta difícil de depurar.
Passo 3: Troque mensagens com postMessage
A comunicação acontece por eventos. No lado principal, worker.postMessage(dados). No worker, self.onmessage = (evento) => { ... }. Para devolver, self.postMessage(resultado). Os dados são copiados, não compartilhados, a menos que você use transferable objects, como ArrayBuffer. Em volumes grandes, essa cópia pode custar caro.
Cuidado: enviar objetos enormes a cada mensagem pode anular o ganho. Prefira lotes menores e estruturas enxutas.
Passo 4: Trate erros e finalize o worker
Worker também falha. Escute worker.onerror e registre a mensagem. Quando a tarefa terminar, chame worker.terminate() para liberar recursos. Um worker esquecido vivo consome memória sem necessidade. Em páginas de longa duração, isso se acumula.
Erro comum: não tratar erro e achar que o worker sumiu. Ele pode estar parado, esperando uma mensagem que nunca chega.
Passo 5: Meça o antes e o depois
Volte ao DevTools e compare. O tempo de resposta ao clique melhorou? As long tasks diminuíram? Se a interface continua travando, o gargalo pode estar em outro lugar, como renderização ou rede. Nem todo problema de performance é thread principal.
Dica: teste em um dispositivo mais lento. O ganho que aparece no seu computador pode não se repetir no celular do usuário.
Checklist rápido
- Identifiquei a tarefa pesada com o DevTools.
- Criei um arquivo de worker separado.
- Usei postMessage para enviar e receber dados.
- Tratei erros com onerror.
- Finalizei o worker com terminate.
- Comparei a performance antes e depois.
FAQ
O que são Web Workers?
São um mecanismo do navegador que permite executar scripts em uma thread separada da principal. Isso evita que tarefas pesadas travem a interface. O worker não acessa o DOM, então serve para cálculos e processamento, não para manipular elementos da página.
Quando devo usar um Web Worker?
Quando uma tarefa de JavaScript demora mais de 50 ms e não depende do DOM. Exemplos: cálculos complexos, ordenação de grandes listas, processamento de imagens. Se a tarefa é rápida ou mexe na interface, o worker não ajuda.
Web Workers podem acessar o DOM?
Não. O worker roda em um escopo isolado, sem window nem document. Para atualizar a tela, ele envia o resultado de volta à thread principal por postMessage, e o código principal faz a alteração. Essa separação é intencional.
Qual a diferença entre postMessage e transferable objects?
postMessage copia os dados enviados. Transferable objects, como ArrayBuffer, transferem a posse sem copiar, o que é mais rápido para volumes grandes. Depois da transferência, o lado que enviou perde o acesso ao objeto. Use quando o volume justificar.
Web Workers funcionam em todos os navegadores?
O suporte é amplo nos navegadores modernos. Ainda assim, vale verificar o comportamento no ambiente do seu público. Em cenários específicos, como extensões ou contextos restritos, pode haver limitações. Teste antes de depender só do worker.
Posso usar vários Web Workers ao mesmo tempo?
Sim, é possível criar vários. Cada um roda em sua própria thread, mas todos competem pelos mesmos recursos do dispositivo. Criar workers demais pode piorar a performance. Comece com um e só aumente se a medição indicar necessidade.
Se você chegou até aqui, talvez já tenha uma tarefa em mente. Vale a pena parar pra pensar: o que na sua página realmente precisa de uma thread separada, e o que só parece pesado?