3 erros que atrapalham (e muito) a performance do seu JavaScript.

Tempo de leitura: 5 minutos

E se eu dissesse que é mentira tudo o que você sabia? O que acontecerá se você descobrir que algumas das principais características do ECMAScript publicadas nos últimos anos são armadilhas de desempenho perigosas?

Esta história começa há alguns anos atrás, nos dias ingênuos do ES5…

Parece que foi ontem que o ES5 foi lançado, e novas funções de array foram introduzidas no nosso querido JavaScript. Entre eles, forEach, reduce, map, filter… Bom, eles nos fizeram sentir que a linguagem está crescendo, ficando mais funcional, o código de escrita se tornou mais divertido e tranquilo, e o resultado foi mais fácil de ler e entender. Certo?

Mais ou menos na mesma época, um novo ambiente cresceu – o Node.js, que nos deu a capacidade de fazer uma transição suave do front-end para o back-end, ao mesmo tempo em que realmente redefiniria o desenvolvimento full stack.

Atualmente, o Node.js, usando o ECS mais recente sobre o V8 (máquina virtual Javascript, desenvolvido pela Google e utilizado em seu navegador Google Chrome), está tentando ser considerado como parte das principais linguagens de desenvolvimento do lado do servidor e, como tal, precisa ser digno de desempenho. Sim, existem muitos parâmetros a serem levados em consideração, e não existe uma linguagem de bala de prata que seja superior a todos. Mas, escrever seu código JavaScript pensando fora da caixa como a função array mencionada acima, está ajudando ou prejudicando o desempenho do seu aplicativo?

Além disso, o javascript do lado do cliente está afirmando ser uma solução razoável para mais do que apenas apresentação, enquanto os computadores dos usuários finais se fortalecem e as redes mais rapidamente ainda, podemos confiar nisto quando nosso aplicativo exige desempenho rápido e pode ser um muito grande e complexo?

Para testar essas perguntas, tentei comparar alguns cenários e detalhar os resultados obtidos. Executei os testes a seguir no Node.js v10.11.0 e no navegador Chrome, ambos no macOS.

  1. Looping sobre um array

O primeiro cenário que me veio à mente foi somar uma array de 10k itens, esta é uma solução válida da vida real que eu tropecei ao tentar buscar uma longa tabela de itens do banco de dados e aumentá-lo com a soma total, sem ter um adicional consulta ao banco de dados.

Eu comparei a soma dos itens aleatórios de 10k usando for, for-of, while, forEach e reduce. A execução dos testes 10.000 vezes retornou os seguintes resultados:

For, tempo médio de loop: ~ 10 microssegundos

For-Of, tempo médio de loop: ~ 110 microssegundos

ForEach, tempo médio de loop: ~ 77 microssegundos

While, tempo médio de loop: ~ 11 microssegundos

Reduce, tempo médio de loop: ~ 113 microssegundos

Enquanto pesquisava como somar um array, reduce era a solução mais oferecida, mas é a mais lenta. Meu objetivo não era muito melhor. Até mesmo o mais novo for-of (ES6) fornece desempenho inferior. Acontece que o bom e velho For (e também While) fornece o melhor desempenho de longe – 10x melhor!

Como a solução mais recente e recomendada pode tornar o JavaScript muito mais lento? A causa dessa dor vem de duas razões principais, Reduce e forEach, uma função de call back a ser executada que é chamada recursivamente e enche a pilha, e a operação e verificação adicionais que são feitas sobre o código executado.

  1. Duplicando um array

Embora isso pareça um cenário menos interessante, esse é o pilar de funções imutáveis, que não modifica a entrada ao gerar uma saída.

As descobertas do teste de desempenho mostram novamente a mesma tendência interessante – ao duplicar 10k arrays de 10k itens aleatórios, é mais rápido usar as soluções antigas. Novamente, a mais moderna operação de espalhamento ES6 `[… arr]` e Array de `Array.from (arr)` mais o mapa ES5 `arr.map (x => x)` são inferiores ao segmento veterano `arr.slice () `e concatenar` [] .concat (arr) `.

Duplicar usando Slice, média: ~ 367 microssegundos

Duplicar usando Map, média: ~ 469 microssegundos

Duplicar usando Spread, média: ~ 512 microssegundos

Duplicar usando Conct, média: ~ 366 microssegundos

Duplicar usando Array From, média: ~ 1.436 microssegundos

Duplicar manualmente, em média: ~ 412 microssegundos

  1. Iterando com Objetos

Outro cenário frequente é iterar os objetos. Isso é necessário principalmente quando tentamos percorrer JSONs e objetos, e não estamos procurando por um valor de chave específico. Novamente, existem as soluções veteranas como o for-in `para (let key in obj)`, ou o mais tardar `Object.keys (obj)` (apresentado em es6) e `Object.entries (obj)` (do ES8) que retorna chave e valor.

A análise de desempenho de 10k objetos iterações, cada uma das quais contém 1.000 chaves aleatórias e valores, usando os métodos acima, revela o seguinte.

For-In, média: ~ 240 microssegundos

Keys for Each, média: ~ 294 microssegundos

Entradas For-Of, média: ~ 535 microssegundos

A causa é a criação de array enumerável de valores nas duas soluções posteriores, em vez de percorrer o objeto diretamente sem o array de chaves. Mas o resultado final ainda está causando preocupações.

Conclusão

Se o desempenho rápido é a chave para a sua aplicação, ou se seus servidores precisam lidar com alguma carga – usar as opções mais limpas e mais legíveis, dará um grande impacto no desempenho do seu aplicativo – que pode chegar a 10 vezes mais devagar!

Da próxima vez, antes de adotar cegamente as novas tendências, certifique-se de que elas também estejam alinhadas às suas necessidades – para um aplicativo pequeno, escrever rápido e um código mais legível é perfeito – mas para servidores estressados e grandes aplicativos do lado cliente, isso pode não ser a melhor prática.

Gostou do conteúdo? Não deixe de seguir a uebile nas redes sociais, pois toda semana tem post novo aqui no blog com mais dicas para o seu impulso digital.