Diminuir Load Times no Carregamento de Páginas Web

Um aspecto muito importante que é necessário ter em conta aquando do desenvolvimento de páginas web é a acessibilidade de uma página e do tempo que a página demora a estar pronta para ser utilizada, pois caso o tempo de carregamento (load time) seja elevado, os visitantes não vão gostar podendo até retroceder e não voltar a essa página, logo load times elevados correspondem quase que directamente a visitantes / utilizadores / membros / clientes perdidos.

Tempo de carregamento baixo = – tempo perdido = utilizador contente

Então podemos concluir que é necessário diminuir os tempos de carregamento das páginas e neste artigo vão ser abordadas várias formas de como reduzir os tempos de carregamento tendo em conta a optimização do JavaScript, do CSS, das imagens bem como optimização do lado do servidor nomeadamente com a utilização de PHP.

JavaScript

O JavaScript é uma linguagem que tem vindo, sucessivamente, a tornar-se cada vez mais popular entre os programadores de webservices pois tem aplicações desde a passagem de argumentos para o servidor sem ser necessário recarregar a página até aos efeitos que o JavaScript permite adicionar às páginas e seus elementos. Mas, infelizmente, todas estas funcionalidades e coisas boas que o JavaScript traz tem um preço… Muitas vezes os ficheiros JavaScript tornam-se muito pesados, quer por serem bibliotecas como a jQuery, MooTools, dojo, ExtJS, etc. ou mesmo porque desenvolvemos grande parte da interface recorrendo a esta linguagem, o que vai adicionar centenas de kilobytes de informação às páginas. E o utilizador é exigente, quer páginas com tempos de carregamento baixos, mas também gosta de todas as facilidades e das interfaces que o JavaScript lhe proporciona. Assim, torna-se necessário, para não causar descontentamento no utilizador, correlacionar estes dois aspectos, é importante encontrar um ponto de equilibro. Como encontrar um ponto de equilibro entre a utilização “massiva” de JavaScript e a exigência dos utilizadores?

Conteúdo duplicado para quê?

Sim, pode parecer óbvio que não se deve ter o mesmo script repetido na mesma página mas é algo que é muito comum e vai gerar dois pedidos HTTP por cada componente a descarregar e utilizar mais capacidade de processamento por parte do browser do utilizador, factores que levam a que a página demore mais tempo a ser carregada inutilmente. Verifique sempre se não tem conteúdo duplicado por acaso! Uma outra solução é utilizar PHP, ou outra linguagem server-side, para adicionar os ficheiros JavaScript ao HTML e verificar se já foi adicionado ou não, tornando assim o código mais profissional e menos susceptivel a falhas e/ou faltas de atenção / verificação.

Colocar os scripts no fundo da página

O grande problema com os scripts é que os browsers não permitem descarregar mais nenhum componente externo enquanto está a descarregar um script. Para optimizar o carregamento da página é então aconselhável que se movam os scripts para o fundo do body, no entanto, existem scripts que não podem ser movidos para o fundo pois passam conteúdo valioso para a página (por exemplo). Uma solução alternativa é utilizar o atributo defer.

“When set, this boolean attribute provides a hint to the user agent that the script is not going to generate any document content (e.g., no “document.write” in javascript) and thus, the user agent can continue parsing and rendering.” (ver aqui)

Assim ao utilizar o atributo defer estamos a dizer ao browser que pode continuar a carregar a página e carregar o script apenas no fim. O que vai reduzir substancialmente o tempo de carregamento, tal como é pretendido.

Descarregar ficheiros em paralelo

Caso façamos uma introdução “normal” na nossa página de ficheiros JavaScript isso vai fazer com que os ficheiros sejam descarregados um de cada vez, diminuindo assim o tempo de carregamento da página.

(...)


(...)

Not Parallel Download

Utilizando a forma normal de inserir os scripts na página vai acontecer que o script2.js só começa a ser descarregado depois do script1.js estar completamente descarregado. Mas para quê esta espera se os acessos de hoje são de banda larga e suportam altas velocidades? Podemos descarregar ambos paralelamente, ao mesmo tempo.

Caso os ficheiros sejam descarregados de forma paralela o tempo de carregamento da página vai diminuir, e como podemos fazer isso? É tão simples como saber utilizar o document.write

(...)

(...)

Parallel Download

Como podemos observar, o segundo exemplo permite que os ficheiros sejam descarregados mais rápidamente pois o download é efectuado ao mesmo tempo. Para mais informações sobre downloads em paralelo continue a ler o artigo e na secção Server-Side este tema será novamente abordado.

Ferramentas para a optimização de código JavaScript

CSS

Todas as páginas web utilizam folhas de estilo (CSS -Cascading Style Sheets) e dependendo do design e da estrutura da folha de estilo esta pode ser maior ou menor mas em ambos os casos leva tempo a carregar e esse tempo deve, tal como nos outros pontos abordados neste artigo, de ser diminuido ao máximo! Além da validação sempre necessária vão ser apresentadas algumas formas de optimizar o código CSS. (validar CSS aqui).

Folhas de estilo no topo

Colocar as folhas de estilo no topo da página faz com que as páginas possam carregar progressivamente e que o utilizador vá vendo o design a surgir. É muito importante dar aos utilizadores um feedback visual mal seja possível (ver estudo aqui), no caso de uma página web a estrutura da página é o nosso indicador de progressão no carregamento da página. Ao carregar a estrutura progressivamente da página (exemplo: header -> menu -> left sidebar -> contéudo) tudo isto vai servir como feedback visual para o visitante que está à espera da página. Caso as folhas de estilo aparecessem mais para o fim, o utilizador enquanto a página fosse carregando iria ter um visual sem estilo algum, sem uma ordem, e por isso pode facilmente desinteressar-se pela página. É também uma especificação HTML dada pelo World Wide Web Consortium (ver aqui

).

Optimizar o Código CSS

Existem várias formas de se optimizar o código CSS sem reduzir de forma alguma as suas capacidades tornando apenas o código mais pequeno e mais conciso. Exemplo:

#div_xpto {
padding-top:15px;
padding-bottom:10px;
padding-left:13px;
padding-right:0px;
}

Neste exemplo podem ser feitas duas alterações de forma a optimizar o código. Unir as componentes da propriedade padding na própria propriedade. A ordem é sempre  top, right, bottom, left (Menomónica possível: TR BL ou sentido dos ponteiros do relógio( Dica de: http://bit.ly/cY3W9G).

#div_xpto {padding: 15px 0px 10px 13px;}

Em vez de utilizarmos 6 linhas utilizamos 1 linha, obtendo o mesmo efeito. Neste exemplo existe ainda outra modificação que podemos fazer que é a de retirar caracteres desnecessários.

#div_xpto {padding: 15px 0 10px 13px;}

Como é possível verificar foi retirado depois do 0 os caracteres px porque 0 é uma medida igual quer em pt, px, em, etc. logo é tempo de carregamento (devido a ser um ficheiro menor) que ganhamos. Caso as medidas padding-top e padding-bottom sejam iguais é possível utilizarmos algo assim: (consideremos as medidas top e bottom de 15px)

#div_xpto {padding: 15px 0 10px; }

Ou seja combinar a componente top e a componente bottom na mesma. Também a nível do background (quase todos os websites utilizam esta propriedade) devem ser feitas optimizações:

div {
background-image:url("fundo.jpg");
background-color:#ffffff;
background-repeat:repeat-x;
background-position:top center;
}

Passa a:

div {
background:url("fundo.jpg") #fff top center repeat-x;
}

Neste exemplo fizeram-se duas alterações, passaram-se as várias componentes do background tudo para a propriedade sem particionamento e a cor passou de #ffffff a #fff. Esta útlima alteração das cores também pode ser utilizada de forma a optimizar o código. Se se definam cores utilizando o standard de 6 digitos este pode ser definido apenas por 3 digitos em certos casos. Como por exemplo: Preto #000000 passa para #000 Branco #ffffff passa para #fff Verde #99ff33 passa para #9f3 Orange #ffcc00 passa para #fc0 Vermelho #ff3300 passa para #f30 Mas por exemplo #930f14 já não pode ser simplificada. Esta técnica funciona para todas as cores seguras (ver aqui tabela). É também muito comum uma outra optmização a nível do código CSS que é combinar elementos. Se tivermos dois elementos que tenham certas caracteristicas iguais, então em vez de se definir duas vezes a mesma caracteristica define-se apenas uma vez englobando ambos os elementos o que torna o código mais limpo e mais leve. Exemplo:

p {
border:0;
padding:0;
margin:0;
font-size:13px;
color:#000
}
.texto {
border:0;
padding:0;
margin:0;
font-size:13px;
color:#360
}

Como podemos reparar as caracteristicas border, padding margin e font-size são idênticas quer na tag p quer na class .texto. Assim em vez de se definirem essas propriedades duas vezes podem ser definidas apenas uma:

p, .texto {
border:0;
padding:0;
margin:0;
font-size:13px;
}

Ferramentas para Optimização de CSS

Leitura complementar:

JavaScript / CSS

JavaScript e CSS em ficheiros externos

Uma pergunta que se faz muitas vezes é se os ficheiros JavaScript e os ficheiros CSS devem estar em ficheiros à parte ou na própria página. Utilizar ficheiros externos torna as páginas mais rápidas porque os ficheiros ficam na cache do browser equanto que se estiverem na página são descarregados sempre que é feito um pedido do documento, assim, ao utilizar ficheiros externos, reduz-se o tamanho da página mas aumenta-se o número de pedidos HTTP, contudo, os ficheiros externos ficam na cache do browser, logo diminui-se os pedidos HTTP e o tamanho da página utilizando ficheiros externos. Além da optimização da página, utilizar ficheiros externos torna o código mais estruturado, mais fácilmente editável e mais limpo sendo então uma boa prática para manutenção da página.

Imagens

Os designs mais eye-candy com a utilização de vários icons para descrever serviços, os efeitos dos fundos, dos headers, dos footers, etc. utilizam bastantes imagens, maiores ou menores mas que, de qualquer modo, levam a que o tempo de carregamento da página seja maior. E o que há fazer? São só imagens… Há alguns truques que podem ser utilizados para aumentar a velocidade de carregamento de imagens.

Não redimensione imagens em HTML!

Este ponto é de facto importante, muitas vezes carregam-se imagens, imaginemos, de 500x500px e depois em HTML definem-se medidas menores, isto é desnecessário e vai obrigar a que uma imagem maior seja carregada em vez de uma menor. Ou seja, em vez de se fazer algo assim

Imagem xpto

com a imagem image.png a ter um tamanho de 500x500px deve-se ter

Imagem xpto

tendo a imagem image.png o tamanho de 50x50px.

É também importante manter sempre as dimensões da imagem mesmo quando ela é exacta, isto é, no caso anterior mesmo já tendo a imagem 50x50px como queremos devemos indicar width=”50px” height=”50px” porque deste modo o browser não tem de “medir” a imagem antes de a colocar na página ficando então da seguinte forma:

Imagem xpto

Obrigado ao Sérgio Dinis Lopes pela dica.

favicon.ico pequeno e armazenável em cache

O favicon.ico é uma pequena imagem que se encontra na raíz do servidor (normalmente). É muitas vezes um problema porque mesmo não existindo o browser vai fazer um request à sua procura por isso é sempre bom ter uma para não se responder com um erro 404 Not Found. Esta pequena imagem interfere também com a sequência de carregamento da página por exemplo no browser Internet Explorer enquanto que os scripts, css, imagens, etc são pedidos no onload event o favicon é pedido antes. Sugestões:

  • Pequeno, de preferência com um máximo de ~1K (exemplos: wikipedia 318 bytes; google 1150 bytes; twitter 1406 bytes; wordpress 1150 bytes);
  • Defina o parâmetro Expires com um valor que ache mais correcto (4 meses é um valor aceitável tendo em conta que não se muda de favicon ferquentemente);

Escolher o Formato Correcto para as Imagens

Existem vários formatos de imagens utilizados na construção de páginas web, entre elas destacam-se os formatos gif, jpeg, png e é importante escolher para cada imagem qual o formato que melhor se lhe adequa fazendo com que imagens com menos pormenores, menos cores, etc. utilizem formatos mais leves (ver mais informações aqui).

Leitura complementar:

Server-Side

Nos tempos de carregamento também interferem as acções do lado do servidor e por isso é necessário optimizar essas acções o máximo possível.

Descarregar o buffer de saída mais cedo

Quando uma página é pedida existe um intervalo de tempo em que o browser espera que o servidor junte o HTML e o envie para o browser. Durante este tempo o browser está inactivo à espera da resposta. A linguagem de programação PHP tem uma função chamada flush que permite que sejam enviadas respostas para o browser particionadas permitindo ao browser começar logo a carregar as informações recebidas enquanto o servidor continua a gerar o resto do HTML.

Downloads em Paralelo

(imagens utilizadas neste subcapitulo retiradas daqui)

A especificação HTTP/1.1 sugere que os browsers façam apenas dois downloads em paralelo de cada dominio assim caso todos os componentes estejam no mesmo dominio só poderão ser feitos dois downloads de cada vez aumentando muito o tempo que uma página demora a carregar.

Clients that use persistent connections SHOULD limit the number of simultaneous connections that they maintain to a given server. A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy.

Dois Downloads em Paralelo

Neste exemplo, estão representados 10 componentes extra na nossa página que precisam de ser descarregados, então se criarmos subdominios conseguimos optimizar o download dos componentes colocando-os a ser descarregados em paralelo. Apesar de se poderem adicionar quantos sub-dominios quiserem às páginas não se devem utilizar mais do que 2-4 dominios devido ao tempo que demora a fazer a correspondência nos DNS (hostname <-> IP) e esta demora, normalmente, entre 20 e 120 millisegundos, enquanto isto acontece o browser não descarrega nada do dominio em questão. E então como resolver a situação? O HTML fica no main-domain http://joaopedropereira.com/ e podem ser criados entre dois e quatro sub-dominios para as imagens content1.joaopedropereira.com e content2.joaopedropereira.com e (sub-dominios apenas com fins ilustrativos). Four Parallel Downloads Assim conseguimos optimizar o tempo de carregamento das imagens e scripts da página. Neste exemplo foi possível poupar algum tempo, quanto mais scripts e imagens existirem mais diferença se fará notar no tempo de carregamento da página.

Leitura Complementar

Utilizar o método GET ou POST em AJAX?

Ao utilizar XMLHttpRequest, o método POST consiste em dois processos separados de envio de informações, primeiro envia os cabeçalhos e só depois envia a informação enquanto que o método GET envia a informação de uma só vez (excepto se existirem muitos cookies). Existe também limite no envio de informações utilizando o método GET pois este não foi feito para enviar grandes quantidades de informações. Tal como os nomes indicam o método GET foi desenhado para pedir informações ao servidor enquanto que o método POST foi desenhado para enviar informações para o servidor. Então qual deles escolher? Na verdade não existe um melhor, existem dois métodos diferentes para situações diferentes e o que é melhor em determinada situação pode não o ser numa outra situação diferente. Então é necessário avaliar cada caso e escolher qual o método mais apropriado.

Leitura Complementar

Quer saber mais?

Existem mais maneiras de optimizar um website mas que podem ser mais complexas ou mais dispendiosas, mas vou aqui deixar links para quem quiser estudar mais sobre este tema.

17 comments

  1. Grande artigo João!

    Gostaria de acrescentar algo que o João se esqueceu.
    Em relação a não redimensionar as imagens via HTML, recomendaria que se inserisse o comprimento e altura da imagem no HTML, desta forma o browser ao renderizar não necessita de “medir” a imagem. 🙂

    Sérgio

    1. Tem razão Sérgio, esqueci-me mesmo de referir esse aspecto. É um aspecto que é muito simples e eficaz, não custa nada escrever as medidas no código para poupar trabalho ao browser.
      Obrigado pela dica vou adicionar ao artigo 😉

  2. Gostei muito deste artigo, sim senhor. Passaste por todos os aspectos que conheço, e ainda deu para aprender mais alguns 😀 . No entanto, fiquei com uma dúvida:
    Ali nos scripts escreveste que o browser faz o download de cada um individualmente, mas se forem “obtidos” escrevendo o document.write com as respectivas declarações, são carregados em simultâneo. O método de pipelining não se aplica em ambos os casos?

    E por fim, uma sugestão ali para a parte das imagens: podias ter falado dos sprites, aquelas imagens que contém praticamente todos os icones e evitam fazer um novo request HTTP por cada. Tens por exemplo, no http://www.delicious.com a funcionar (http://l.yimg.com/hr/img/del_sprite_largeIcons.gif para todos os icones dos “titulos”), que depois são obtidos os icones respectivos por CSS. Até existem serviços na web, uma pesquisa no motor de busca por “sprites generator” deve ser esclarecedora 😉

    1. softclean obrigado pelos elogios mas vamos às criticas e sugestões que não são menos importantes.

      O pipelining só se aplica no caso da utilização do método document.write (existem outros métodos mas dos dois em questão é o único) pois os browsers estão estruturados de forma a que quando presentes de um script só descarreguem um de cada vez, e não só faz download de cada script um de cada vez como enquanto está a descarregar um script não permite que mais nenhum elemento externo seja descarregado.

      Eu não falei em sprites mas coloquei uma ligação externa para um excelente artigo que fala sobre sprites no sub-tópico Leitura Complementar no tópico CSS. Sendo o artigo o seguinte: http://www.alistapart.com/articles/sprites/
      Mas sim, foi de facto uma falha minha, já que abordei todos aqueles temas podia também ter abordado sprites…
      Obrigado.

  3. Grande artigo João!
    Ajuda bastante em grandes aspectos e deixa os visitantes muito felizes!
    Agradeço a tua partilha, muito deles também conhecia, outros aprendo contigo 🙂
    Continua com o excelente desenvolvimento.
    Dá-me só uma ideia, necessito de um sistema de votação para o meu site o que me aconselhas?
    Abraço.

  4. Olá João!, Excelente artigo. Li-o com a atenção devida e quero-te dar os parabéns pela forma como abordas os diversos conteúdos e fazes referências a outros sites relevantes.
    Fica aqui a mensagem que prometo acompanhar regularmente o teu blog, bem como assinar o rss feed por e-mail.. 🙂
    Quando ao artigo…o único reparo é em relação ao CSS.
    Quando falas em optimizar isto:

    div {

    background-image:url("fundo.jpg");
    background-color:#ffffff;
    background-repeat:repeat-x;
    background-position:top center;
    }
    
    para isto:
    
    div {
    background:url("fundo.jpg") #fff top center repeat-x;
    }
    
    É óptimo todos saberem como se realiza este tipo de passagens,
    no entanto não é uma solução eficiente, pois o Internet Explorer
    não gosta deste tipo de optimização e geralmente não sintetiza a imagem. 
    Não sei especificar se é uma versão em específico do IE ou se todas, 
    de qualquer modo é preferível usar a primeira opcção. 
    
    Cumprimentos,
    Continua assim com estes posts, adoro ler estas coisas :)
    Abraço 
    
    
    1. Mário Freitas, obrigado pelo apoio.

      Pedro Magalhães, obrigado pelo apoio e pelo reparo.
      Na verdade, não tinha conhecimento desse problema no Internet Explorer, vou verificar essa falha e depois dou mais feedback.

  5. Andava eu à procura de uma forma de acelerar o carregamento do meu blog apenas através da optimização do CSS e dou com este artigo que explora várias formas de acelerar… Excelente!

    Estás de parabéns!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.