Usando o plugin Immersive Translate para traduzir alguns sites com LLM, notei travamentos do mouse; algumas sugestões do LLM

E além disso, a travada só é reproduzível em alguns sites. Pedi para o LLM ler um pouco do código do plugin; daqui a pouco vou chamar alguém mais experiente para ver se tem alguma ideia de otimização.

Do ponto de vista da arquitetura e da implementação do desenvolvimento de plugins, para os gargalos de desempenho causados pela tradução por LLM, é possível fazer uma otimização profunda a partir das seguintes dimensões centrais:

  1. Introduzir uma arquitetura de processamento assíncrono (Web Workers)
    Atualmente, uma grande quantidade de correspondência por regex, parsing de HTML e comparação de textos traduzidos do plugin pode estar sendo executada no Content Script (thread principal).
  • Solução de otimização: migrar para o Web Worker a lógica que não envolve operação direta no DOM (como parsing do protocolo de streaming do LLM, pré-processamento de texto, algoritmos de comparação multilíngue).
    .
  • Efeito: liberar a thread principal, garantindo que, ao mesmo tempo em que o navegador processa os dados de tradução, ele ainda responda ao scroll e aos cliques do usuário a 60 fps.
  1. Implementar “renderização em lote” e “fatiamento de tempo” (Scheduling)
    Em saída por streaming (Streaming), o mais problemático é receber um caractere e atualizar o DOM uma vez.
  • Solução de otimização:
    • Atualização com buffer (Buffering): definir um buffer de 100 ms–200 ms, mesclar vários fragmentos retornados pelo LLM e, em seguida, iniciar uma única atualização do DOM via
      requestAnimationFrame.
    • Fatiamento de tempo (Time Slicing): se for preciso inserir muitos nós de tradução de uma vez, usar uma ideia semelhante ao React Fiber,
      decompondo a tarefa em várias subtarefas pequenas e inserindo-as uma a uma quando o navegador estiver ocioso (requestIdleCallback).
  • Efeito: transformar o reflow originalmente denso em atualizações ritmadas, reduzindo drasticamente a carga instantânea de CPU.
  1. “Renderização preguiçosa” baseada na viewport (Intersection Observer)
    Se a página for muito longa, a tradução completa fará com que milhares de nós do DOM sejam atualizados simultaneamente em segundo plano, mesmo que esses nós não estejam na tela.
  • Solução de otimização: usar a API IntersectionObserver.
    • Apenas quando o nó do texto original entrar na viewport (ou estiver prestes a entrar) é que se dispara a solicitação de tradução e se monta o DOM de tradução.
    • Para nós de tradução que saíram muito da viewport, pode-se considerar destruí-los ou ocultá-los temporariamente para reduzir a pressão de cálculo de layout do navegador.
  • Efeito: reduzir a quantidade de computação de “escala da página inteira” para “escala da tela”.
  1. Otimizar a estratégia de montagem do DOM (Containment)
    Ao inserir nós de tradução, se o layout original for quebrado, isso levará ao reflow de toda a página.
  • Solução de otimização:
    • CSS Containment: adicionar contain: layout; ou contain:
      content; ao contêiner traduzido. Isso informa ao navegador que mudanças internas desse nó não afetarão o layout externo.
    • Placeholder fixo: antes de iniciar a tradução, estimar um espaço reservado de altura com base no comprimento do texto original, evitando que, durante o streaming do texto traduzido, a página “treme” repetidamente.
  • Efeito: limitar o escopo do reflow, evitando que “uma mudança pequena afete o todo”.
  1. Reduzir disparos excessivos do MutationObserver
    Como o próprio plugin modifica o DOM, isso acionará novamente seu próprio listener do MutationObserver.
  • Solução de otimização:
    • Ao inserir nós de tradução, bloquear temporariamente o listener por meio de um flag global (Flag) ou, no listener, filtrar os nós gerados pelo próprio plugin via node.isTrusted
      ou atributos específicos.
    • Aumentar dinamicamente o limiar de mutationChangeDelay: ao detectar que o usuário está rolando rapidamente, aumentar automaticamente o atraso ou pausar o scan.
  1. “Atualização incremental” em vez de “substituição total” na saída por streaming
  • Solução de otimização: se o nó de tradução for um contêiner, durante a atualização por streaming deve-se apenas anexar nós de texto, em vez de fazer innerHTML = …
    reconstruindo a estrutura interna a cada vez.
  • Efeito: reduzir a pressão de coleta de lixo (GC) de memória e o overhead de parsing da árvore do DOM.

Resumo
O caminho de otimização mais eficaz é: Web Worker para processar dados →
requestAnimationFrame para renderização com buffer →
IntersectionObserver para limitar o escopo →
CSS contain para isolar o layout. Assim, é possível desacoplar perfeitamente a “carga pesada” do LLM da “fluidez” do navegador.


Ao ativar a tradução por llm, a CPU salta instantaneamente de 5 para uma carga de 50.