Otimização ou como não dar um tiro no próprio pé

Bom dia a todos. Hoje eu quero falar com você sobre otimização. O que é, por que é necessário e, o mais importante, como garantir que não dói dolorosamente então.


Primeiro, entenderemos o que é otimização em geral e o que é otimização em JS. Então, otimização é a melhoria de algo de acordo com alguma característica quantitativa. JS identificou quatro características quantitativas para si:


A quantidade de código - geralmente é aceito que quanto menos linhas de código escritas, mais produtivo e melhor. Minha opinião é fundamentalmente diferente, porque, ao escrever uma linha de código, você pode criar um vazamento de memória ou ciclo perpétuo que o navegador simplesmente morre.


Velocidade (desempenho) é a chamada complexidade computacional, ou seja, o número de ações que o analisador precisará executar para executar a instrução.


Velocidade de construção - não é segredo que agora quase nenhum dos projetos pode ficar sem construtores como Webpack ou Gulp, portanto, esse recurso exibe a correção das configurações do construtor de projetos. Acredite, quando o servidor é um pouco mais inteligente que o moedor de café, isso se torna importante.


Reutilização de código - essa característica mostra como a arquitetura para reutilizar funções, componentes e módulos é construída.
Considere cada uma das categorias com mais detalhes; analisaremos quais características ela inclui e do que depende.


Volume do código:

  • Dobragem. Quanto código do mesmo tipo foi escrito em lugares diferentes;
  • Comentários Os comentários no código são bons, mas me deparei com projetos nos quais havia mais comentários do que código;
  • Falta de unificação. Um bom exemplo desse problema são funções semelhantes, que têm nuances dependendo de algumas propriedades.
  • A presença de código morto. Frequentemente, em projetos, existem funções de depuração ou funções que não são usadas.

Desempenho:


  • Usando o mecanismo de cache do navegador;
  • Otimização de código com base nos ambientes em que será executado;
  • A presença de vazamentos de memória;
  • Usando trabalhadores da Web;
  • Usando referências a elementos da árvore DOM;
  • Uso de variáveis ​​globais;
  • A presença de chamadas recursivas;
  • Simplificação de cálculos matemáticos.

Velocidade de construção:


  • O número de dependências externas;
  • Conversões de código. Isso se refere ao número de blocos e seu tamanho, conversões de css, colagem de arquivos, otimização de gráficos e muito mais.

Reutilização de código:


  • Número de componentes;
  • Repetibilidade dos componentes
  • Flexibilidade e personalização.

Como dito nos artigos anteriores, para mudar alguma coisa, você precisa determinar o ponto de partida e descobrir como tudo está ruim. Por onde começar um processo tão volumoso? Comece com a coisa mais simples: acelerar a montagem e reduzir o tempo de excesso do projeto. Você pergunta por que vale a pena começar com isso? Devido ao fato de que eles dependem um do outro. Reduzir a quantidade de código aumentará a velocidade de compilação e, consequentemente, aumentará sua produtividade.


A otimização do tempo de compilação inevitavelmente nos apresenta o conceito de compilação "Cold" - este é o processo em que um projeto inicia do zero e até o ponto em que todas as dependências são afetadas e o código é completamente recompilado. Não confunda com Rebild - isso está reconstruindo o código do cliente sem extrair dependências externas e outros enfeites.


Aumentar a velocidade de compilação ajudará:


  • Usando montadores modernos. As tecnologias não param e, se você tiver o primeiro pacote da web, quando passar para o quarto, verá um aumento agradável já sem fazer nada;
  • Livrar-se de todos os vícios mortos. De tempos em tempos, os desenvolvedores, tentando encontrar a verdade na parte inferior da lata de ácido sulfúrico, esquecem-se de limpar após seus próprios experimentos. Meu colega perguntou uma vez: “Faça dependências escritas no package.json, mas não importadas em nenhum lugar do código, entre no pacote o pacote? " Sim, eles não serão incluídos na própria montagem, mas a embalagem será esvaziada. A questão é, por quê?
  • Divida a montagem em vários perfis, dependendo de suas necessidades. Mínimo dois: prod e dev. Caso em questão: ofuscação do código. No prod, isso é obrigatório, pois menos peso = carregamento mais rápido, mas no ofuscamento do desenvolvedor, apenas interfere e gasta o tempo de construção em manipulações desnecessárias;
  • Paralelização de etapas individuais de montagem;
  • Usando clientes npm que podem armazenar em cache.

Acelerar a reconstrução e a compilação "fria" exigirá cortar comentários desnecessários e trechos de código mortos. No entanto, o que fazer se você tiver um projeto enorme e não for possível inspecioná-lo? Nesses casos, os analisadores de código vêm em socorro.


Pessoalmente, uso periodicamente o SonarQube , não o melhor, mas flexível. Pode ser ensinado os recursos do projeto, se houver. De tempos em tempos, ele faz coisas que ao menos permanecem, ao menos caem, mas, como qualquer instrumento, ele deve ser capaz de usá-lo e não se esqueça de ser cético em relação a seus comentários. Apesar de todas as suas desvantagens, ele lida com a busca por códigos mortos, comentários, a presença de copiar e colar e pequenas coisas, como a falta de uma comparação rigorosa.


A principal diferença entre o SonarQube e o ESlint / TSLint / Prettier e outros semelhantes é que ele verifica a qualidade do código, isola a duplicação, a complexidade do cálculo e também fornece recomendações sobre as alterações necessárias. Os análogos simplesmente verificam o código quanto a erros, sintaxe e formatação.


Na prática, me deparei com o codacy , um bom serviço com uma assinatura gratuita e paga. Será útil se você precisar verificar algo ao lado, sem ter que implantar esse 'harvester' em casa. Possui uma interface intuitiva, uma indicação detalhada do que há de errado com o código e muito mais.


Neste artigo, não abordarei o tópico de configuração da compilação, partes e o restante, porque tudo depende das necessidades do projeto e do construtor instalado. Talvez eu fale sobre isso em outros artigos.


As manipulações feitas ajudaram a acelerar a montagem - lucro, mas e depois? Como os analisadores podem encontrar a duplicação de código, será útil colocá-lo em módulos ou componentes separados, aumentando assim a reutilização de código.


Havia apenas uma seção em que não tocamos - a velocidade do próprio código. O próprio mecanismo de gerar um senso de produtividade é chamado por toda a odiada refatoração de palavras. Vamos dar uma olhada no que vale a pena fazer ao refatorar e no que não é.


Regra de vida: se funcionar, não toque, não deve guiá-lo nesse processo. A primeira regra na TI: faça um backup e você agradecerá a si mesmo. Na frente, antes de fazer alterações, faça testes para não perder a funcionalidade no futuro. Então pergunte a si mesmo - como determinar os tempos de carregamento e vazamentos de memória?


Isso ajudará o DevTool. Ele não apenas mostra um vazamento de memória, informa o tempo de carregamento da página, a redução da animação e, se você tiver sorte, realizará uma auditoria para você, mas isso não é exato. O DevTools também possui um recurso interessante, como limitar a velocidade de download, o que permitirá prever a velocidade de carregamento da página com pouca Internet.


Conseguimos identificar os problemas, agora vamos resolvê-los!


Para começar, reduziremos o tempo de carregamento usando o mecanismo de cache do navegador. O navegador pode armazenar em cache tudo e, posteriormente, fornecer ao usuário os dados do cache. Armazenamento local e armazenamento de sessão que ninguém tirou de você. Eles permitem que você armazene alguns dos dados que ajudam a acelerar o SPA durante downloads subsequentes e reduzir solicitações desnecessárias do servidor.


Considera-se necessário otimizar o código com base no ambiente em que será executado, mas, como mostra a prática, consome muito tempo e esforço, sem gerar um aumento tangível. Proponho considerar isso apenas como uma recomendação.
É naturalmente aconselhável eliminar todos os vazamentos de memória. Não vou me concentrar nisso, acho que todo mundo sabe como eliminá-los e, se não, basta pesquisar no Google.


Outro de nossos assistentes é um webworker. Trabalhadores da Web são threads de propriedade do navegador que podem ser usados ​​para executar o código JS sem bloquear o loop de eventos. Os trabalhadores da Web podem executar tarefas computacionalmente pesadas e demoradas sem bloquear o fluxo da interface do usuário. De fato, quando são usados, os cálculos são realizados em paralelo. Antes de nós é real multithreading. Existem três tipos de trabalhadores da Web:


  1. Trabalhadores dedicados - Instâncias de trabalhadores da web dedicados são criadas pelo processo principal. Somente o próprio processo pode trocar dados com eles.
  2. Trabalhadores compartilhados (trabalhadores compartilhados) - O acesso a um trabalhador compartilhado pode ser obtido por qualquer processo que tenha a mesma origem do trabalhador (por exemplo, guias diferentes do navegador, iframe e outros trabalhadores compartilhados).
  3. Trabalhadores de serviço são trabalhadores controlados por eventos registrados usando sua origem e caminho. Eles podem controlar a página da web à qual estão vinculados, interceptando e modificando comandos de navegação e solicitações de recursos e armazenando em cache dados que podem ser controlados com muita precisão. Tudo isso nos fornece excelentes ferramentas para controlar o comportamento do aplicativo em uma determinada situação (por exemplo, quando a rede está indisponível).

Como trabalhar com eles pode ser facilmente encontrado na Internet.


Nós meio que descobrimos as abordagens e os elogios de terceiros, agora proponho falar sobre o próprio código.


Primeiro, tente se livrar das chamadas diretas para a árvore DOM, pois essa é uma operação demorada. Vamos imaginar que você esteja constantemente manipulando algum tipo de objeto no seu código. Em vez de trabalhar com esse objeto por referência, você constantemente puxa a árvore DOM para procurar e trabalhar com esse elemento, e implementamos o padrão de cache no código.


O segundo passo é livrar-se das variáveis ​​globais. O ES6 nos deu uma maravilhosa invenção da humanidade chamada variáveis ​​de bloco (em termos simples, declarações de variáveis ​​de var para let e const ).


E, finalmente, o mais delicioso. Infelizmente, aqui nem todos têm experiência suficiente para entender as nuances. Sou contra o uso de funções recursivas. Sim, eles reduzem a quantidade de código escrito, mas isso não ocorre sem problemas: geralmente essas funções recursivas não têm condições de saída, são simplesmente esquecidas. Como no ditado "você pode quebrar um dedo com um martelo, mas isso não é um problema do martelo, mas um proprietário do dedo" ou uma piada sobre gatos: funções recursivas não são ruins, você precisa ser capaz de cozinhá-las.


Apesar de todo o poder dos aplicativos front-end modernos, você não deve esquecer o básico. Um exemplo claro de desperdício e irracionalidade é a adição de novos elementos ao início da matriz. Quem sabe, ele entendeu, e quem não sabe - agora vou contar. Todo mundo sabe que os elementos da matriz têm seu próprio índice e, quando adicionarmos um novo elemento à matriz, a sequência de ações será a seguinte:


  1. Definição do comprimento da matriz
  2. Numeração de cada elemento.
  3. Mudança de cada elemento da matriz
  4. Inserir um novo item em uma matriz
  5. Reindexando elementos da matriz.

Resumo:


Chegou a hora de encerrar e, para quem se sentir confortável com o formato dos memorandos, mantenha uma lista de etapas, graças às quais você pode entender em que estágio de otimização está agora e o que fazer em seguida:


  1. Determinamos o quanto tudo é bom / ruim, removemos as métricas.
  2. Cortamos tudo o que é desnecessário: dependências não utilizadas, código morto, comentários desnecessários.
  3. Personalizamos e agilizamos o tempo de montagem, configuramos diferentes perfis para os contornos.
  4. Analisamos o código e decidimos quais partes serão otimizadas e reescritas.
  5. Estamos escrevendo testes para evitar a perda de funcionalidade.
  6. Começamos a refatorar, nos livramos de variáveis ​​globais, vazamentos de memória, código de dublagem e outros tipos de lixo e não esquecemos o cache.
  7. Simplificamos a complexidade dos cálculos e levamos todo o possível para o web worker.

Tudo não é tão complicado quanto parece à primeira vista. Sua sequência provavelmente será diferente da minha, apenas porque você tem a cabeça nos ombros. Você adiciona novos itens ou, ao contrário, reduz o número deles, mas a base da lista será semelhante. Descrevi especificamente a divisão para que essa atividade pudesse ser executada paralelamente ao trabalho principal. Muitas vezes, o cliente não está pronto para pagar pelo retrabalho, concorda?


E finalmente


Eu acredito em você e você terá sucesso. Você acha que eu sou ingênuo? Suponho que você ficará surpreso, mas desde que você encontrou este artigo, leia-o até o final, significa (tenho boas notícias para você) que você tem cérebro e está tentando desenvolvê-lo. Desejo-lhe sucesso em um empreendimento tão difícil como otimizar a frente!

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


All Articles