Desenvolvimento de JavaScript responsável, parte 1

Os números nos dizem que o crescimento do código JavaScript afeta negativamente o desempenho dos projetos da web. Se isso continuar mais, muito em breve, ao carregar a página do meio, pelo menos 400 Kb de código JS serão transferidos. E essa é apenas a quantidade de dados transferidos. Como outros recursos de texto, o código JavaScript é quase sempre transmitido em um formato compactado. A compactação é provavelmente a única coisa que geralmente é feita corretamente ao transferir o código do servidor para o cliente.

imagem

Infelizmente, embora reduzir o tempo de transferência de determinados recursos contribua seriamente para o que chamamos de "desempenho", a compactação não afeta o tempo que o navegador leva para analisar e processar o script depois que ele é totalmente carregado. .

Se o servidor enviar 400 KB de código JS compactado para o cliente, a quantidade real de código que o navegador precisa processar após descompactar os dados recebidos estará na área de megabytes. O quão bem os dispositivos diferentes lidam com esse tipo de trabalho depende dos próprios dispositivos. Muito foi escrito sobre isso, mas só podemos dizer com certeza que o tempo necessário para analisar a quantidade de código bastante usual para o seu tempo varia muito entre dispositivos diferentes.

Veja, por exemplo, esse meu projeto simples. Durante o carregamento da página, cerca de 23 Kb de código JS não compactado são transferidos para o cliente. O Chrome, rodando no MacBook Pro, lançado em meados de 2017, processa essa quantidade bastante pequena de código em cerca de 25 ms. No smartphone Nokia 2 Android, no entanto, um número semelhante se expande para 190 ms. Isso não quer dizer que seja muito pequeno, mas, de qualquer forma, a página se torna interativa com rapidez suficiente.

Agora, uma pergunta importante. O que você acha, como um simples smartphone Nokia 2 gerencia páginas médias modernas? De fato - simplesmente horrível. A navegação em páginas da Web, mesmo em uma conexão rápida à Internet, força o usuário a ter paciência, pois trabalhar com páginas carregadas com código JavaScript só é possível após um período de espera pesado.


Visão geral de desempenho do Nokia 2 ao visualizar uma página que contém uma grande quantidade de código JS, cujo processamento bloqueia o encadeamento principal

Embora os dispositivos com os quais eles usam para navegar nas páginas da Web e as redes através das quais os dados são transmitidos tenham melhorado significativamente nos últimos anos, estudos mostram que todas essas melhorias são "consumidas" por grandes quantidades de código JS incluído nas páginas. Precisamos usar o JavaScript com responsabilidade. A responsabilidade começa com a compreensão do que estamos criando e como fazemos.

Comparação da ideologia de "sites" e "aplicativos"


Coisas estranhas acontecem com termos imprecisos que usamos para nomear alguma coisa, embora seus significados, em um nível intuitivo, sejam claros para todos. Às vezes, sobrecarregamos o significado da palavra “abelha”, chamando-a de “abelhas” e vespas, mesmo que a diferença entre abelhas e vespas seja muito significativa. Levar em consideração essas diferenças pode levar ao fato de que as “abelhas” e “vespas” agirão de maneira diferente. Por exemplo, vamos destruir um ninho de vespas, mas se estamos falando de abelhas, os insetos são muito mais úteis e vulneráveis, provavelmente o ninho localizado no lugar errado provavelmente não será destruído, mas transferido para algum lugar.

Liberdade semelhante pode ser observada na maneira como usamos os termos "site" e "aplicativo da web". As diferenças entre esses conceitos são muito menos óbvias do que as diferenças entre vespas reais e abelhas, mas se esses conceitos forem combinados, isso pode levar a consequências muito desagradáveis. Os problemas começam quando nos permitimos algo, dependendo se um projeto é "apenas um site" ou "um aplicativo da Web completo". Se você estiver criando um site de informações para uma empresa, provavelmente não dependerá de uma estrutura poderosa para gerenciar alterações no DOM ou implementar o roteamento no cliente. No mínimo, espero que sim. O uso de ferramentas inadequadas para resolver certos problemas não só prejudicará quem usará o site, mas provavelmente também afetará muito o processo de desenvolvimento.

Ao desenvolver um aplicativo da Web, tudo parece diferente. Instalamos pacotes, que são acompanhados pela adição de centenas, senão milhares, de dependências ao projeto. Além disso, nem temos certeza da segurança de alguns deles. Escrevemos configurações complexas para empacotadores. Ao trabalhar em um ambiente de desenvolvimento louco e onipresente, você precisa de conhecimento e atenção para garantir que o que foi coletado seja rápido, que o projeto funcione onde deve funcionar. Em caso de dúvida, execute o comando npm ls --prod no diretório raiz do seu projeto e veja se você pode nomear o propósito de usar tudo o que esse comando exibe. Mesmo que você possa fazer isso, isso não se aplica a scripts de terceiros. Estou certo de que vários desses scripts também são usados ​​no seu projeto.

Esquecemos que sites e aplicativos da web ocupam o mesmo "nicho ecológico". Ambos estão sob a mesma influência do ambiente, que consiste em uma variedade de redes e dispositivos. Tais restrições não desaparecerão se decidirmos chamar o que estamos desenvolvendo como um "aplicativo", e os dispositivos de nossos usuários não se tornarão magicamente muito mais rápidos se chamarmos o "site" de "aplicativo".

É nossa responsabilidade descobrir quem usa o que criamos. Devemos levar em conta o fato de que as condições sob as quais diferentes usuários se conectam à Internet podem diferir daquelas em que confiamos. Ao criar algo, precisamos conhecer o objetivo para o qual estamos criando e, depois disso, devemos desenvolver o que ajuda a alcançar esse objetivo - mesmo que o desenvolvimento não seja um empreendimento tão empolgante .

Isso significa a necessidade de reavaliar nossa dependência do JavaScript e como seu uso, em particular em detrimento do HTML e CSS, pode nos levar ao uso de padrões irracionais que prejudicam o desempenho e a acessibilidade dos projetos da Web.

Não permita que estruturas imponham padrões irracionais a você


Testemunhei a descoberta de coisas estranhas nas bases de código quando trabalhei com equipes, dependendo das estruturas, para ajudá-las a serem mais produtivas. Muitas dessas descobertas têm uma coisa em comum: a maneira como são escritas geralmente leva a problemas com a disponibilidade e o desempenho dos sites. Por exemplo, considere o seguinte componente React:

import React, { Component } from "react"; import { validateEmail } from "helpers/validation"; class SignupForm extends Component {  constructor (props) {    this.handleSubmit = this.handleSubmit.bind(this);    this.updateEmail = this.updateEmail.bind(this);    this.state.email = "";  }  updateEmail (event) {    this.setState({      email: event.target.value    });  }  handleSubmit () {    //      -      if (validateEmail(this.state.email)) {      // ...    }  }  render () {    return (      <div>        <span class="email-label">Enter your email:</span>        <input type="text" id="email" onChange={this.updateEmail} />        <button onClick={this.handleSubmit}>Sign Up</button>      </div>    );  } } 

Aqui você encontra vários problemas importantes relacionados à acessibilidade do projeto:

  1. Um formulário que não usa o elemento <form> não é mais um formulário. De fato, você pode corrigir isso simplesmente especificando o papel = "formulário" do elemento pai <div> , mas se você criar um formulário e o que vemos definitivamente parecer um formulário, use o elemento <form> , configurando-o de acordo atribui action e method . O atributo action desempenha um papel crucial aqui, pois permite que o formulário faça pelo menos algo, mesmo que o JavaScript não esteja disponível (naturalmente, se o componente foi renderizado no servidor).
  2. A <span> não substitui a <label> , que fornece alguns recursos relacionados à disponibilidade de projetos que o <span> não possui.
  3. O elemento <button> sem o atributo type="submit" é apenas um botão, clicando no qual chama o manipulador de eventos associado a ele. Se queremos fazer alguma coisa com os dados antes de enviar o formulário, precisamos atribuir o atributo type="submit" ao botão e mover o código do manipulador de eventos onClick para o manipulador de eventos do formulário onSubmit .
  4. A propósito, por que usar o JavaScript para verificar endereços de email, enquanto o HTML5 coloca à nossa disposição controles que oferecem suporte à verificação de dados de entrada em quase todos os navegadores - até o IE10? Aqui vemos uma oportunidade perdida de aproveitar a funcionalidade que já está no navegador e aplicar o tipo de elemento apropriado, bem como o atributo necessário . No entanto, usando essas construções, lembre-se de que a configuração de sua interação normal com os leitores de tela exigirá algum esforço .

Considerando o exposto, refatoramos o código do componente:

 import React, { Component } from "react"; class SignupForm extends Component { constructor (props) {   this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit (event) {   //    ,         XHR   // (      ,     ,     JS).   event.preventDefault();   //  … } render () {   return (     <form method="POST" action="/signup" onSubmit={this.handleSubmit}>       <label for="email" class="email-label">Enter your email:</label>       <input type="email" id="email" required />       <button type="submit">Sign Up</button>     </form>   ); } } 

Agora, o fato de esse componente renderizar não apenas se torna mais acessível, mas menos código JS é usado para implementar a mesma funcionalidade de antes. Em um mundo que literalmente se afogou em JavaScript, livrar-se de algumas linhas de código deve ser visto como algo positivo. O navegador nos oferece muitas oportunidades , e precisamos nos esforçar para usá-las o mais rápido possível.

Não quero dizer aqui que problemas com acessibilidade de páginas surgem exclusivamente ao usar determinadas estruturas. Quero dizer, confiando demais em JavaScript, o desenvolvedor, como resultado, simplesmente perderá muitos recursos importantes de HTML e CSS. Essas lacunas no conhecimento geralmente levam a erros; além disso, nem suspeitamos desses erros. As estruturas podem ser ferramentas úteis que aumentam a produtividade do desenvolvedor, mas o estudo constante dos recursos das tecnologias básicas da Web é extremamente importante na criação de produtos convenientes e utilizáveis, independentemente das ferramentas auxiliares usadas em seu desenvolvimento.

Confie no poder da plataforma web e dê um futuro brilhante a seus projetos


Como estamos falando de estruturas, deve-se notar que a plataforma web, por si só, também é uma estrutura enorme. Conforme mostrado na seção anterior, nos encontramos em uma posição melhor se pudermos confiar nos padrões estabelecidos para trabalhar com os recursos de marcação e navegador. Uma alternativa para esses recursos padrão é inventá-los novamente. Desnecessário dizer que essa "invenção" está repleta de dificuldades consideráveis. Mas e se esses problemas, cada um à sua maneira, fossem resolvidos pelos autores de todos os pacotes JavaScript que instalamos?

Applications Aplicações de página única


Um dos pontos fracos dos desenvolvedores que eles podem pagar facilmente é o uso do modelo de aplicativo de página única (SPA), mesmo nos projetos para os quais esse modelo não é adequado. Obviamente, esses projetos se beneficiam do fato de serem percebidos pelos usuários como mais produtivos devido ao roteamento realizado pelo cliente. Mas quais são as desvantagens de usar o modelo SPA? Os recursos internos de navegação da página do navegador, embora construídos em um modelo síncrono, oferecem ao projeto muitas vantagens. Uma delas é que o gerenciamento do histórico de visitas é realizado através da implementação de especificações complexas . Usuários sem JavaScript, desabilitados ou não , não perderão a capacidade de trabalhar com o projeto. Para que um aplicativo de uma página esteja disponível em navegadores com JavaScript desativado, repentinamente acontece que uma atenção considerável deve ser dada à renderização do servidor.


Comparação de diferentes opções para carregar um aplicativo experimental em um canal de comunicação lento. A renderização do aplicativo à esquerda depende completamente do JavaScript. O aplicativo à direita é renderizado no servidor, mas depois usa no cliente o método hydrate () para conectar os componentes à marcação já criada no servidor

Aqui você pode ver que o aplicativo, que é renderizado no cliente, por alguns segundos mostra ao usuário uma tela em branco e exibe a interface finalizada.

Um aplicativo que é renderizado no servidor e operacional no cliente exibe rapidamente os principais elementos da interface, mas você pode usá-lo após aproximadamente o mesmo tempo que o aplicativo que é renderizado inteiramente no cliente.

A disponibilidade do aplicativo também sofre se o roteador localizado no cliente não puder informar o usuário sobre o que foi alterado na página que ele está visualizando. Isso pode forçar o usuário a confiar em tecnologias de assistência para descobrir o que exatamente mudou na página. Como resultado, o trabalho do usuário com o site é muito mais complicado.

Além disso, você pode encontrar imediatamente nosso antigo inimigo - uma carga excessiva no sistema. Alguns roteadores clientes são muito pequenos. Mas se você criar um projeto no React , usar um roteador compatível e, possivelmente, uma biblioteca para gerenciar o estado do aplicativo, isso significa que você deve aceitar que ele contenha uma certa quantidade de código de serviço, do qual você não pode chegar a lugar algum. Nomeadamente, neste caso, são aproximadamente 135 Kb desse código. Analise cuidadosamente os projetos que você está criando e se o roteamento do cliente vale a carga adicional no sistema. Geralmente acontece que é melhor recusar o sistema de roteamento do cliente.

Se você está preocupado com os sentimentos do usuário, se deseja que o site pareça rápido para ele, pode confiar no atributo rel = prefetch link, que permite organizar o pré-carregamento de documentos da mesma fonte. O uso desse atributo tem um enorme impacto na melhoria do desempenho do projeto, percebido pelos usuários, pois as páginas vinculadas ao uso desse atributo, quando você clica nesses links, são instantaneamente carregadas do cache. Além disso, como o pré-carregamento de dados tem baixa prioridade, é improvável que concorra pela largura de banda com recursos importantes.


O código HTML mencionado por escrito / é pré-carregado quando você visita a página principal do site. Quando um usuário clica no link correspondente, o código HTML é carregado instantaneamente no cache do navegador

O principal problema que pode surgir com as páginas de pré-carregamento e das quais você precisa estar ciente é que esse carregamento pode se tornar um desperdício de tempo e recursos. Para resolvê-lo, você pode, por exemplo, usar o pequeno script Quicklink do Google, que atenua esse problema. Ele verifica se o cliente atual está usando uma conexão lenta, se o modo de economia de dados está ativado e, por padrão, permite evitar o pré-carregamento de materiais de fontes diferentes da fonte da página.

Para fazer com que o site pareça rápido aos olhos dos usuários que o visitam muitas vezes, você pode usar profissionais de serviço . Eles podem ser usados ​​independentemente de o projeto usar ou não um sistema de roteamento de clientes, considerando que você está familiarizado com alguns dos recursos dos profissionais de serviço. Ao executar o cache de rota por meio de profissionais de serviço, obtemos muitas das mesmas vantagens características para o download antecipado de alguns links, mas temos possibilidades muito mais extensas para trabalhar com solicitações e respostas. Se você percebe seu site como um "aplicativo" ou não, equipá-lo com um técnico de serviço é provavelmente um exemplo de um dos casos de uso de JavaScript mais críticos do nosso tempo.

AvaJavaScript não foi projetado para layout


Se instalarmos um pacote JS projetado para resolver problemas relacionados aos layouts de página, é hora de sermos muito cuidadosos e nos perguntarmos o que estamos tentando alcançar com este pacote. O CSS foi criado especificamente para criar layouts de página. Para usá-lo de maneira eficaz, você não precisa de abstrações. A maioria das tarefas de criação de layouts que eles tentam resolver usando JavaScript, como colocar elementos, alinhar, ajustar seus tamanhos, como manipular texto ou até mesmo criar layouts completamente usando JavaScript, agora pode ser realizada usando CSS. Ferramentas modernas para criar layouts como Flexbox e Grid são bem suportadas pelos navegadores, portanto, não precisamos desenvolver projetos baseados em estruturas para trabalhar com layouts. A propósito, CSS também é uma estrutura. Quando temos à disposição uma oportunidade como solicitações de propriedade , a melhoria progressiva dos layouts para apoiar novos meios de sua formação, como se vê, não é tão difícil .

 /*   , ,   ,        CSS Grid. */ /*  @supports  ,     CSS Grid,     . */ @supports (display: grid) { /*      */ @media (min-width: 40em) {   /*       CSS Grid */ } } 

Usar o JavaScript para resolver os problemas de criação de layouts de página e personalização de aparência não é novidade. Foi o que fizemos em 2009, quando vivíamos em uma atmosfera de auto-engano, dizendo que todos os sites deveriam se parecer no IE6 e nos navegadores mais avançados da época. Se hoje, em 2019, continuamos a desenvolver sites para que eles tenham a mesma aparência em todos os navegadores, isso significa que precisamos reconsiderar nossos objetivos. Sempre haverá alguns navegadores que precisam ser suportados e que não possuem os mesmos recursos que os navegadores mais modernos. A completa semelhança externa de projetos em todas as plataformas não é apenas um desperdício de energia, é também um inimigo fundamental da ideia de melhorias progressivas .

Bottom line: eu não vou me tornar um assassino de JavaScript


Não me interpretem mal, eu não pertenço aos inimigos do JavaScript. Graças a essa linguagem, construí uma carreira e, para ser honesto, o JavaScript, há mais de dez anos, me traz muito prazer. Como em qualquer relacionamento de longo prazo, quanto mais tempo passo trabalhando com JavaScript, melhor eu o conheço. É uma linguagem madura, com muitos recursos, que a cada ano está melhorando.

No entanto, às vezes parece-me que algo deu errado em nosso relacionamento com JavaScript. Eu o critico. Ou, mais precisamente, eu critico a tendência atual de considerar o JavaScript a principal ferramenta de criação de sites, que é usada em primeiro lugar, sem olhar para mais nada. Quando analisei outro pacote que parecia uma guirlanda de Natal confusa, ficou claro para mim que a web estava intoxicada com JavaScript. Recorremos a esse idioma por quase qualquer motivo, mesmo nos casos em que as circunstâncias não exigem isso. Às vezes, penso em quão severas podem ser as consequências dessa atitude em relação à JS.

Eu pretendo continuar escrevendo sobre JavaScript e desenvolvimento web, para continuar procurando maneiras de usar racionalmente as tecnologias web. Esperamos que juntos melhoremos a web moderna.

Caros leitores! Você acha que a Web moderna está realmente sobrecarregada com o código JavaScript?

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


All Articles