Como melhorar o desempenho de aplicativos Web front-end: cinco dicas



Em muitos dos meus projetos de front-end, em algum momento eu me deparei com uma diminuição na produtividade - isso geralmente acontece quando a complexidade do aplicativo aumenta e isso é normal. No entanto, os desenvolvedores ainda são responsáveis ​​pelo desempenho, portanto, em meu artigo, darei cinco dicas para otimizar os aplicativos que me aplico: alguns podem parecer óbvios, outros afetam os princípios básicos da programação - mas, penso, atualizar a memória não é supérfluo será. Cada dica é apoiada por testes: você pode executá-las e testar o desempenho.

Traduzido para Alconost

Prefácio


Lembre-se: se o código não precisar de otimização, não entre nele. Obviamente, o código que você escreve deve funcionar rapidamente, e você sempre pode criar um algoritmo mais rápido - mas o código escrito deve permanecer claro para outros desenvolvedores. Na palestra “Programação como arte”, Donald Knuth expressou uma ideia muito importante sobre otimização de código:

O verdadeiro problema era que os programadores passavam muito tempo se preocupando com a eficiência em locais inapropriados e em momentos inadequados. A otimização prematura é a raiz de todos os erros de programação (ou pelo menos a maioria).

1. Pesquisa: em vez de matrizes comuns - objetos e matrizes associativas


Ao trabalhar com dados, as situações geralmente surgem quando, por exemplo, você precisa encontrar um objeto, fazer algo com ele, depois encontrar outro objeto e assim por diante. A estrutura de dados mais comum em JS é uma matriz, portanto, armazenar dados neles é uma prática normal. No entanto, sempre que você precisar encontrar algo na matriz, precisará usar métodos como "find", "indexOf", "filter" ou iterar com loops - ou seja, você precisará iterar os elementos do início ao fim. Assim, realizamos uma pesquisa linear, cuja complexidade é 0 (n) (na pior das hipóteses, precisaremos realizar tantas comparações quanto elementos na matriz). Se você fizer essa operação algumas vezes em pequenas matrizes, o impacto no desempenho será pequeno. No entanto, se tivermos muitos elementos e a operação for realizada várias vezes, o desempenho certamente falhará.

Nesse caso, será uma boa solução converter um array regular em um objeto ou array associativo e realizar uma pesquisa de chave: nessas estruturas, os elementos podem ser acessados ​​com complexidade O (1) - teremos uma chamada de memória, independentemente do tamanho. Melhorar a velocidade do trabalho é alcançado através do uso de uma estrutura de dados chamada tabela de hash .

Você pode testar o desempenho aqui: https://jsperf.com/finding-element-object-vs-map-vs-array/1 . Abaixo estão meus resultados:



A diferença é muito significativa: para uma matriz associativa e um objeto, recebi milhões de operações por segundo, enquanto para uma matriz, o melhor resultado é um pouco mais de cem operações. Obviamente, a conversão de dados não é levada em consideração aqui, mas mesmo levando em consideração sua operação será muito mais rápida.

2. Em vez de exceções - o operador condicional "se"


Às vezes, parece mais fácil pular a verificação nula e capturar as exceções correspondentes. Obviamente, esse é um mau hábito - você não precisa fazer isso e, se tiver um no seu código, basta reescrever as seções correspondentes. Mas, para convencê-lo completamente, apoiarei essa recomendação com testes. Decidi testar três maneiras de fazer verificações: a expressão “try-catch”, a condição “if” e o cálculo de “short circuit”.

Teste: https://jsperf.com/try-catch-vs-conditions/1 . Abaixo estão meus resultados:



Eu acho que é óbvio daqui que uma verificação de "nulo" é necessária. Além disso, como você pode ver, quase não há diferença entre a condição "se" e o cálculo do "curto-circuito" - então aplique ao que a alma está.

3. Quanto menos ciclos, melhor


Outra consideração óbvia, mas talvez controversa. Existem muitas funções convenientes para matrizes: “mapa”, “filtro”, “redução”, para que seu uso seja atraente, e o código com eles pareça mais limpo e mais fácil de ler. Mas quando surgir a questão de melhorar a produtividade, você pode tentar reduzir o número de funções chamadas. Decidi analisar dois casos: 1) "filtrar", depois "mapear" e 2) "filtrar" e depois "reduzir" - e compará-los com a cadeia funcional, "forEach" e o tradicional "for" loop. Por que exatamente esses dois casos? A partir dos testes, será visto que os benefícios obtidos podem não ser muito significativos. Além disso, no segundo caso, também tentei usar "filtro" ao chamar "reduzir".

Teste de desempenho para "filtro" e "mapa": https://jsperf.com/array-function-chains-vs-single-loop-filter-map/1 . Meus resultados:



Pode-se ver que um ciclo é mais rápido, mas a diferença é pequena. A razão para uma lacuna tão pequena é a operação "push", que não é necessária ao usar o "mapa". Portanto, nesse caso, você pode pensar se é realmente necessário prosseguir para um ciclo.

Agora, verifique "filtro" + "redução": https://jsperf.com/array-function-chains-vs-single-loop-filter-reduce/1 . Meus resultados:



Aqui a diferença já é maior: a combinação de duas funções em uma acelerou a execução em quase metade. No entanto, a transição para o tradicional "for" ciclo dá um aumento muito mais significativo na velocidade.

4. Use regularmente para loops


Esse conselho também pode parecer controverso, porque os desenvolvedores adoram ciclos funcionais: eles são bem lidos e podem simplificar o trabalho. No entanto, eles são menos eficazes que os ciclos tradicionais. Eu acho que você já deve notar a diferença no uso de para loops, mas vamos dar uma olhada em um teste separado: https://jsperf.com/for-loops-in-few-different-ways/ . Como você pode ver, além dos mecanismos internos, também verifiquei "forEach" na biblioteca "Lodash" e "each" em "jQuery". Resultados:



E, novamente, vemos que o loop "for" mais simples é muito mais rápido que o resto. É verdade que esses loops são bons apenas para matrizes - no caso de outros objetos iteráveis, você deve usar "forEach", "for ... of" ou o próprio iterador. Mas "for ... in" deve ser aplicado apenas se não houver outros métodos. Além disso, lembre-se de que "para ... em" aceita todas as propriedades do objeto (e na matriz as propriedades são índices), o que pode levar a resultados imprevisíveis. Surpreendentemente, os métodos do Lodash e do jQuery não eram tão ruins em termos de desempenho; portanto, em alguns casos, você pode usá-los com segurança em vez do “forEach” embutido (é interessante que no teste o loop do Lodash funcionou mais rápido que o embutido).

5. Use as funções internas para trabalhar com o DOM


Às vezes, você olha para o código de outra pessoa e vê que o desenvolvedor importou o jQuery apenas para manipular o DOM - tenho certeza que você também viu isso, porque esta é uma das bibliotecas JavaScript mais populares. É claro que não há nada errado em usar bibliotecas para controlar o DOM: hoje usamos React e Angular, e eles fazem o mesmo. No entanto, algumas vezes parece que o jQuery deve ser usado mesmo para operações simples para extrair um elemento do DOM e fazer pequenas alterações nele.

Aqui está uma comparação das funções internas do DOM e operações similares do JQuery em três casos diferentes: https://jsperf.com/native-dom-functions-vs-jquery/1 . Meus resultados:



E, novamente, as funções mais básicas - "getElementById" e "getElementsByClassName" - acabaram sendo as mais rápidas ao exibir o DOM. No caso de identificadores e seletores avançados, o querySelector também é mais rápido que o jQuery. E em apenas um caso, o "querySelectorAll" é mais lento que o jQuery (obtendo elementos pelo nome da classe). Para obter mais informações sobre como e como substituir o jQuery, consulte aqui: http://youmightnotneedjquery.com .

É claro que, se você já estiver usando a biblioteca para gerenciar o DOM, é altamente recomendável que você se atenha a ela - no entanto, para casos simples, ferramentas internas são suficientes.

Materiais adicionais


Essas cinco dicas ajudarão você a escrever um código JavaScript mais rápido. Mas se você estiver interessado em ler mais sobre otimização de desempenho, aqui estão algumas recomendações:

1. Otimização de pacotes configuráveis ​​JavaScript usando o Webpack: este é um tópico muito extenso, mas se tudo for feito corretamente, o carregamento de aplicativos poderá ser significativamente acelerado.

2. Estruturas de dados, algoritmos básicos e sua complexidade: muitos acreditam que isso é "apenas uma teoria", mas no primeiro parágrafo vimos como essa teoria funciona na prática.

3. Testes na página jsPerf : aqui você pode se familiarizar com uma comparação de diferentes maneiras de realizar a mesma tarefa em JavaScript e, ao mesmo tempo, ver um indicador importante na prática - a diferença de velocidade.

Sobre o tradutor

O artigo foi traduzido por Alconost.

A Alconost localiza jogos , aplicativos e sites em 70 idiomas. Tradutores nativos, testes linguísticos, plataforma em nuvem com API, localização contínua, gerentes de projeto 24/7, qualquer formato de recursos de string.

Também criamos vídeos de publicidade e treinamento - para sites que vendem, imagem, publicidade, treinamento, teasers, exploradores, trailers do Google Play e da App Store.

Leia mais

Source: https://habr.com/ru/post/pt456808/


All Articles