Aguarde...

9 de fevereiro de 2019

Estudo de caso de desempenho de DOM

Estudo de caso de desempenho de DOM

Eu tenho uma pergunta interessante para você – quando você usou pela última vez API DOMverdadeiramente pura e métodos para construir um projeto real? Sim, não me lembro desses tempos também. Did Mas eles sequer existiram? Como você quase sempre usa o HTML com a ajuda da API do DOM para fazer mais coisas interativas, mas não o usa como uma maneira autônoma de criar sua interface do usuário. Mas, com os frameworks e bibliotecas modernos da interface do usuário , como o React , o Vue ou o Angular, os tempos mudaram e também a maneira de criar interfaces de usuário. Então, a menos que você esteja usando algum framework que compila seu códigopara o trio HTML / CSS / JS, é mais provável que você baseie seu aplicativo em alguma ferramenta baseada na API do DOM. 😉 Com isso dito, o nível de controle que essas ferramentas nos fornecem é incrível. Isso realmente ajuda a criar experiências melhores, mais bonitas e mais rápidas . Sim, velocidade – é isso que vamos investigar hoje.

Como você pode saber ou ouvir em algum lugar, qualquer interação com o DOM é cara . Essas chamadas podem causar um grande impacto no desempenho quando você não está usando corretamente. Mesmo se estamos falando de frações de milissegundos, ainda é importante. Se sua interface do usuário não puder funcionar perfeitamente, bloqueada a 60 FPS (+ 1 / -1), algo não está correto. Mas não deve ser o caso do seu aplicativo Vue / React / Angular, a menos, é claro, que você tenha feito algo realmente ruim ou tenha executado tarefas exigentes (BTC mining, WebGL, AI e outras coisas complicadas). Isso é por causa de quão bem otimizadas são essas ferramentas. Então, vamos fazer um estudo de caso aqui e verificar algumas técnicas de otimização de DOM , incluindo o uso dessas bibliotecas, para saber como é feito! Apreciar! 👍


Estudo de caso de desempenho de DOM

Reflows

Começando com o mais notório, aqui vem o refluxo – seu pior inimigo e melhor amigo de uma só vez. Reflow (também chamado de trashing de layout ) é o nome de todos os processos que ocorrem no seu navegador quando você interage com DOM, CSS e todo esse tipo de coisa. Significa re-renderizações e recálculos do layout do seu site (posições e tamanho do elemento). Tudo o que é bom – os refluxos lidam com todas essas complexidades nos bastidores. Vamos passar para a pior parte então – o refluxo é uma operação de bloqueio do usuário ! Isso significa que, se há muito trabalho a ser feito ao executar o refluxo, sua interface do usuário pode reduzir sua taxa de quadros, congelar ou – no pior cenário – até esmagar. Essas são todas as experiências que você provavelmente não deseja que seus usuários tenham. Com isso dito, é importante lidar com o DOM e, assim, resultar em refluxos com cuidado especial.

O que exatamente desencadeia o refluxo então? Há uma ótima lista na forma de GitHub Gist se você quiser saber mais. Mas aqui vamos dar uma rápida olhada no mais importante de todos:

  • getComputedStyle()extremamente útil e extremamente dispendioso ;
  • métricas de caixa e rolagem – coisas como clientHeightscrollTop;
  • propriedades da janela – clientHeightscrollY;
  • dados de posição dos eventos e SVG

Então, esses são apenas os básicos, mais genéricos. Naturalmente, algumas tarefas como acessar uma propriedade têm menos sobrecarga de desempenho (tempo de refluxo) do que alguns métodos mais avançados como getComputedStyle().


Dosagem

Então, reflows não são muito bons. O que podemos fazer para minimizá-los ou, pelo menos, otimizá-los para aumentar o desempenho? 🚀 Bem, na verdade muito. Primeiro, a melhor e mais popular técnica é conhecida como batching . O que basicamente significa é que você deve agrupar suas operações de leitura e gravação DOM e enviá-las separadamente, sempre que possível. Esse processo permite que o navegador otimize suas chamadas sob o capô e resulte em melhoria geral no desempenho.

// This will always be faster...

const width = element.clientWidth + 10;
const width2 = element.clientWidth + 20;

element.style.width = width + 'px';
element.style.width = width2 + 'px';

// ...than this.

const width = element.clientWidth + 10;
element.style.width = width + 'px';
const width2 = element.clientWidth + 10;
element.style.width = width2 + 'px';

Além disso, você também deve agrupar e reduzir qualquer outro tipo de interação DOM. Por exemplo, vamos usar a maneira padrão de adicionar um novo elemento à sua árvore DOM. Quando você está adicionando apenas um ou dois, pode não valer a pena o problema extra. Mas quando estamos falando de dezenas ou centenas de elementos, é realmente importante comprometer essa chamada corretamente. O que eu quero dizer com isso? Bem, basta agrupar todas essas chamadas em uma, provavelmente com a ajuda de DocumentFragment.

// Unoptimized
for(let i = 0; i < 100; i++){
    const element = document.createElement('div');
    document.body.appendChild(element);
}

// Optimized
const fragment = document.createDocumentFragment();
for(let i = 0; i < 100; i++){
    const element = document.createElement('div');
    fragment.appendChild(element);
}
document.body.appendChild(fragment);

Uma mudança tão simples pode levar a uma grande diferença. Eu acho que, escusado será dizer que você deve aplicar a mesma prática / ideia sempre e onde quer que você pode. Além disso, o que também pode ser útil são as ferramentas de desenvolvimento do seu navegador . Você pode usar a linha do tempo de renderização para ver todos os dados relevantes sobre como seu DOM foi renderizado. É claro, só é útil quando você coloca as otimizações adequadas no lugar.


Diversos

Agora, vamos falar sobre coisas mais gerais. O conselho mais óbvio será apenas para manter as coisas simples. Mas o que isso significa em profundidade?

  • Reduza a profundidade do DOM – A complexidade desnecessária apenas torna as coisas mais lentas. Além disso, em muitos casos, quando você atualiza o nó pai, os filhos podem precisar ser atualizados para, assim, resultar na estrutura inteira formada sob o nó especificado que precisa ser processada. A atualização também pode invocar alterações até a árvore DOM. Em suma, faz o refluxo demorar mais tempo.
  • Otimize o CSS – Naturalmente, as regras CSS que não são usadas não são realmente necessárias. Você deve remover qualquer um desses. Em seguida, seletores CSS complexos também podem causar um problema. Mas, se você já seguiu a regra anterior, estas podem ser inúteis, não deixando nenhuma necessidade para elas em seu código. Inlining os estilos que você muda frequentemente é uma boa prática também. Obviamente, em contraste, os estilos que são usados ​​por um número de elementos devem ser feitos separadamente como uma regra de CSS .
  • Animações – Estas podem ser muito difíceis. Você deve limitar suas animações sempre que possível apenas para propriedades de transformação e opacidade. Além disso, é sempre melhor incluí-los fora do fluxo , o que significa definir o positioncomo absoluteou fixed. Isso garante que suas animações não interfiram no restante da interface do usuário, causando refluxos ainda mais lentos. Além disso, informe ao seu navegador que as propriedades especificadas serão alteradas utilizando a will-changepropriedade. E, por último, você pode querer animar usando animações CSS ou API de animação da Web . Desta forma, todas as suas animações são executadas em um “thread de composição”separado e especial, tornando-as não-bloqueantes .

Essas dicas podem melhorar drasticamente seu desempenho! Então, use-os sempre que puder.


Estudo de caso de desempenho de DOM

De perspectiva diferente

Agora que sabemos que os refluxos que lidam com as atualizações de visão para nós são a raiz de todo mal 😈, vamos resumir e dar uma olhada em todas as informações anteriores de uma perspectiva um pouco diferente.

Tudo o que acontece na tela deve manter os 60 FPS sensacionalistas que todos desejam. Isso significa que a tela deve ser atualizada 60 vezes por segundo (ou mais para dispositivos com taxas de atualização mais altas). E o que isso significa, mais especificamente, é que tudo o que acontece neste single frame (JS, reflows e etc.) deve acontecer com menos de 10 ms (na verdade você tem 16 ms, mas o navegador usa 6 ms para tarefas domésticas) . Com isso dito, quando a tarefa é muito grande e demora muito (mais de 10 ms), a taxa de quadros cai e os lags acontecem.

Vamos dar uma olhada neste diagrama para ver exatamente o que acontece neste quadro único:

Estudo de caso de desempenho de DOM

Eu acho que a parte do JavaScript não precisa de mais explicações além de que é o que geralmente desencadeia as mudanças visuais (também pode ser animações CSS, API de animação da Web e etc.).

Estilo marca a hora em que os cálculos de estilo ocorrem. Aqui todas as suas regras CSS são processadas e aplicadas (coisas de seletores CSS).

As etapas de layout e pintura são as mais importantes para nós, porque podem ser facilmente otimizadas. Etapa de layout é o local de origem dos refluxos. Aqui, depois que seus estilos já foram aplicados na etapa anterior, as propriedades que podem exigir o recálculo de geometriaestão sendo manipuladas. Isto inclui widthheightlefttope etc. A mudança dessas propriedades pode exigir para atualizar outros elementos , incluindo os para baixo e no topo da árvore DOM.

O que você pode fazer para otimizar essa etapa é gerenciar as alterações nessas propriedades com sabedoria ou ter uma boa hierarquia DOM que não requeira muitas alterações na atualização de um elemento. Claro, você também pode alterar a positionpropriedade. Um elemento que está fora do fluxo normal não acionará uma mudança em outros elementos. Quando nenhuma propriedade de layout é alterada, o navegador omite essa etapa .

Depois disso vem o passo da pintura . Aqui, as propriedades que não interferem no layout são tratadas. Estes incluem backgroundcolorshadowe afins. Geralmente visuais puros. As reposições não são tão caras quanto as alterações de layout e (como antes) são omitidas quando não são necessárias .

Composto é um passo final, sempre necessário. Aqui todas as camadas criadas anteriormente são coladas para o resultado final. Isso será pintado mais tarde, pixel a pixel, na tela.

Acredito que esses aspectos internos de como tudo isso acontece podem realmente inspirá-lo a descobrir como você pode otimizar seu código. Além disso, se você acha que seu aplicativo é rápido o suficiente sem qualquer otimização, pense no que você poderia fazer com esse poder de computação extra – mais visuais, melhores animações – as opções são praticamente infinitas! 🌟


Uma palavra no DOM virtual

Depois de todos esses truques e dicas, eu acho que agora você pode entender facilmente o que é tão mágico por trás de todo esse DOM virtual que tem sido ultimamente tão popular principalmente pela grande influência que o React e o Vue têm. Ele permite que você mantenha os dados de seus nós visuais em uma forma de estruturas nativas de JS, portanto, não requerendo acesso ao DOM (com reflows e outras coisas como resultado)!

Então, como funciona em poucas palavras? Bem, primeiro você interage com o VDOM e aplica suas alterações nele. Então (eu poderia ter pulado algumas coisas mais detalhadas, mas é muito importante) vem a etapa de reconciliação . Aqui a nova árvore VDOM é comparada com a antiga para diferenciar as mudanças. Estes são posteriormente aplicados ao DOM real.

Agora, a etapa de reconciliação é onde a discussão como React vs Vue (performance-wise) realmente tem suas origens. Essa comparação é praticamente a idéia mais importante e crucial por trás do que é conhecido por muitos como DOM virtual. Este é o lugar onde o React 16 ( React Fiber ) fez um trabalho incrível em otimizações. Mas o Vue é igualmente impressionante, com sua implementação DOM virtual sendo capaz de escolher seletivamente quais nós precisam ser atualizados (em vez de como o React faz isso – atualizando a árvore inteira para baixo). De qualquer forma, estes dois tem feito um bom trabalho em melhorar o desempenho e experiência de desenvolvimento de grande número de programadores JS, então grandes polegares para cima para isso! 👍


Linha de fundo

Espero que este artigo tenha lhe dado algumas dicas sobre como melhorar o desempenho do seu aplicativo baseado em JS / React / Vue / DOM. 😀 Então, não há nada mais a dizer do que ir e tornar a web mais rápida , eu acho. 😄 Como sempre, se você gostou deste artigo, deixe um comentário , compartilhe-o com os botões redondos abaixo e assine as notificações com a barriga à direita.

Postado em BlogTags:
Escreva um comentário