Otimizar a execução do JavaScript

O JavaScript geralmente aciona mudanças visuais. Às vezes, diretamente por meio de manipulações de estilo, outras vezes, por cálculos que resultam em mudanças visuais, como pesquisar ou classificar dados. JavaScript de longa duração ou no momento errado é uma causa comum de problemas de desempenho. Você deve minimizar o impacto dele sempre que possível.

O JavaScript geralmente aciona mudanças visuais. Às vezes, isso é diretamente manipulações de estilo e, às vezes, por cálculos resultar em mudanças visuais, como pesquisar ou classificar dados. No momento certo ou JavaScript de longa duração é uma causa comum de problemas de desempenho. Você deve minimizar o impacto dele sempre que possível.

A criação de perfis de desempenho do JavaScript pode ser uma arte, porque o JavaScript que você escreve é nada como o código que é realmente executado. Os navegadores modernos usam compiladores JIT e de todas as formas de otimizações e truques para tentar oferecer a execução mais rápida possível, e isso muda substancialmente a dinâmica do código.

No entanto, com tudo isso dito, há algumas coisas que você pode fazer para ajudar seus apps a serem executados muito bem em JavaScript.

Resumo

  • Evite setTimeout ou setInterval para atualizações visuais. sempre use requestAnimationFrame.
  • Mova o JavaScript de longa duração da linha de execução principal para os Web Workers.
  • Use microtarefas para fazer alterações no DOM ao longo de vários frames.
  • Use a Linha do tempo e o JavaScript Profiler do Chrome DevTools para avaliar o impacto do JavaScript.

Usar requestAnimationFrame para mudanças visuais

Quando mudanças visuais estão acontecendo na tela, você quer fazer seu trabalho no momento certo para do navegador, que está bem no início do frame. A única maneira de garantir que o JavaScript será executada no início de um frame é usar requestAnimationFrame.

/**
    * If run as a requestAnimationFrame callback, this
    * will be run at the start of the frame.
    */
function updateScreen(time) {
    // Make visual updates here.
}

requestAnimationFrame(updateScreen);

Frameworks ou amostras podem usar setTimeout ou setInterval para fazer mudanças visuais, como animações, mas o problema é que o callback será executado em algum ponto no frame, possivelmente correto no final, o que pode resultar na perda de um frame, resultando em instabilidade.

setTimeout faz com que o navegador perca um frame.

Na verdade, o jQuery costumava usar a setTimeout para o comportamento animate. Ele foi alterado para usar requestAnimationFrame na versão 3. Se estiver usando uma versão antiga do jQuery, você pode corrigi-lo para usar requestAnimationFrame, o que é altamente recomendado.

Reduza a complexidade ou use Web Workers

O JavaScript é executado na sequência principal do navegador, junto com cálculos de estilo, layout e, em muitos casos, pintura. Se o JavaScript for executado por muito tempo, ele bloqueará essas outras tarefas, pode causar a perda de frames.

Você deve ser tático em relação a quando o JavaScript é executado e por quanto tempo. Por exemplo, se você estiver em um como a rolagem, o ideal é manter o JavaScript em algo região de 3-4ms. Um tempo maior que isso pode levar muito tempo. Se você estiver em um modo ocioso pode se dar ao luxo de se sentir mais relaxado em relação ao tempo gasto.

Em muitos casos é possível migrar o trabalho computacional puro para Web Workers, se, por exemplo, não exigir acesso ao DOM. A manipulação ou travessia de dados classificação ou pesquisa, geralmente são boas opções para este modelo, assim como o carregamento e a geração de modelos.

var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);

// The main thread is now free to continue working on other things...

dataSortWorker.addEventListener('message', function(evt) {
    var sortedData = evt.data;
    // Update data on screen...
});

Nem todo trabalho pode se adequar a esse modelo: os Web Workers não têm acesso ao DOM. Quando seu trabalho precisar estar na linha de execução principal, considere uma abordagem em lote, em que você segmenta a tarefa maior em microtarefas, cada uma com menos de alguns milissegundos, e é executada dentro de gerenciadores requestAnimationFrame em cada frame.

Essa abordagem tem consequências para a UX e a interface, e você precisa garantir que o usuário saiba de que uma tarefa está sendo processada, usando um indicador de progresso ou de atividade. De qualquer forma, essa abordagem vai manter a linha de execução principal do app sem custos, ajudando a manter a capacidade de resposta interações do usuário.

Conheça a "taxa de frames" do JavaScript

Ao avaliar um framework, uma biblioteca ou seu próprio código, quanto custa executar o código JavaScript frame a frame. Isso é especialmente importante ao fazer trabalhos de animação em que o desempenho é crítico, como transição ou rolagem.

O painel "Desempenho" do Chrome DevTools é a melhor forma de medir Custo do JavaScript. Normalmente, você recebe registros de baixo nível como estes:

Uma gravação de desempenho no Chrome DevTools

A seção Principal apresenta um Flame Chart de chamadas JavaScript para que você consegue analisar exatamente quais funções foram chamadas e quanto tempo cada uma levou.

Com essas informações, você pode avaliar o impacto no desempenho o JavaScript no seu aplicativo, além de encontrar e corrigir pontos de acesso em que funções estão demorando muito para serem executadas. Como mencionado anteriormente, você deve procurar remover o JavaScript de longa duração ou, se isso não for possível, movê-lo para um web worker, liberando a linha de execução principal para continuar com outras tarefas.

Consulte Introdução à análise do desempenho do ambiente de execução para aprender a usar no painel "Desempenho".

Evite a microotimização do JavaScript

Pode ser legal saber que o navegador pode executar uma versão de algo 100 vezes mais rápido do que por exemplo, solicitar o offsetTop de um elemento é mais rápido do que calcular getBoundingClientRect(), mas é quase sempre verdade que você só chamará funções como um pequeno número de vezes por frame, então normalmente é desperdiçado esforço se concentrar nesse aspecto da o desempenho do JavaScript. Normalmente, você economiza apenas frações de milissegundos.

Se você está criando um jogo ou um aplicativo computacionalmente caro, provavelmente é uma exceção. a essa orientação, pois você normalmente encaixará muita computação em um único frame e, caso tudo ajude.

Resumindo, você deve ser muito cauteloso com micro-otimizações porque elas não costumam ser mapeadas na e o tipo de aplicativo que você está criando.