Nova versão do jQuery Lazy Load

Conversando com o Rafael Cavalcante sexta ele me lembrou que eu ainda devia melhorias para aplicar no jQuery Lazy Load Plugin.

Comecei sexta e testei hoje, está tudo no Github.

jQuery Lazy Load Changelog

  • Melhoria de performance
  • Não precisa mais de classe para trabalhar

Changelog detalhado:

Devido as preocupações com performance de javascript mudei um pouco forma como o plugin trabalha.

Com o uso do grep no lugar do each, o jQuery Lazy Load está agora removendo do seu array  todas as imagens que já for carregadas. Elas não são percorridas repetidamente (como acontecia na versão 0.5) e a performance melhorou bastante por conta disso.

Também por conta desta nova forma de trabalhar com o array não é mais necessário o uso de classe (a classe era utilizada para verificar se uma imagem já havia sido carregada). Como preciso manipular menos o DOM também houve ganho de performance por conta disso.

 

Como usar o jQuery Lazy Load

Baixa a última versão do plugin no Github.

Chamando os scripts

Chame o jQuery e o jQuery Lazy Load plugin na sua página.

Preparando as imagens

As imagens que utilizarão o lazy load devem ter a tag data-src com o valor da url da imagem que deverá ser carregada no conteúdo.

Uma dica é chamar o src das imagens para uma imagem transparente e sempre estipular a largura e altura da imagem no próprio HTML, assim sua página vai renderizar mais rápido pois você irá reduzir o reflow do browser.

Outra dica é através de CSS colocar uma imagem de loader como background das imagens que utilizarão o plugin de lazy load, assim se as imagens demorarem para carregar seu usuário terá uma experiência melhor e saberá que algo está acontecendo.

 

Iniciando o Lazy Load

Por último, é só iniciar o plugin com o seletor das imagens que irão utilizar o plugin:

$(function() {
$('.lazy').lazyLoad();
});

 

Pronto, agora seus usuários só carregarão imagens quando necessário.

Javascript: como alterar o intervalo de um timeout?

Estou estudando NodeJS (veja como instalar o NodeJS no Ubuntu) e meu interesse por javascript aumentou com isso – comecei projetos para estudar desenvolvimento de games em javascript.  Nesses estudos percebi que o  setInterval e setTimeout são grandes ferramentas para a criação de scripts complexos, mas que são pouco explorados normalmente. 

Como alterar o interval no Javascript?

Supondo que você instanciou uma função para ser executada 10 segundos depois que o usuário entrar na página (setTimeout). Mas caso o usuário clique no botão Y esta função tem que ter um novo delay, novamente de 10 segundos.

Não encontrei uma maneira de alterar um timeout ou interval em andamento, então a lógica é cancelar o timer que está em funcionamento e setar um novo timer, com o intervalo desejado.

Vamos por partes, cancelando a função já instanciada.

 

Como cancelar um setTimeout em javascript

Nosso código:

var agendamento = setTimeout(function(){
 console.log('ação agendada!');
}, 1000);

/* Cancela o agendamento */
clearTimeout(agendamento);

Simples assim! 

Alterando o intervalo com ação do usuário

var agendamento = setTimeout(function(){
 console.log('ação agendada!');
}, 1000);

$('a.cancela').click(function(){
 clearTimeout(agendamento);
 var agendamento = setTimeout(function(){
  console.log('ação agendada!');
 }, 1000);
});

 

Poderia melhorar o código transformando a criação do agendamento em uma função, mas optei por deixar o mais legível para facilitar o entendimento.

Tem alguma forma diferente de fazer isso? Deixe um comentário!

O que é browser reflow?

Com o crescimento da banda larga e a evolução da web como um todo, a preocupação de performance deixou de ser exclusividades dos desenvolvedores back-end e se tornou uma grande preocupação de front-end.

Essas preocupações me levaram a melhorar muito meu código javascript (vejas estas dicas de performance em javascript) e aqui no iG comecei a estudar melhor a forma que os navegadores trabalham a fim de melhorar a performance desde a parte do HTML.

O que é browser reflow?

O "browser reflow" é uma tarefa do navegador que calcula o posicionamento e dimensão de todos os elementos da sua página. O navegador percorre toda a árvore DOM mesclando a estrutura do HTML com o CSS (externou ou inline) que fica na "style structure", isso forma a Render Tree, que é o que nós visualizamos.

A cada reflow, todos os elementos tem o tamanho e reposição calculadas, por isso que um excesso de reflow causa mais processamento e consequentemente páginas com uma renderização mais demorada.

Para entender melhor o que é um reflow, assista o vídeo de como o navegador renderiza o HTML, neste mesmo post.

O que é um repaint?

Repaint é quando acontece uma alteração visual no elemento (cor, background) que não altera suas dimensões (margem, padding, largura ou altura). O repaint é menos custoso em termos de processamento.

 

Minimzando o browser reflow

Agora que você já sabe o que é reflow e sabe o impacto na performance da exibição da página, a redução do desse processamento se torna mais importante para saber como fazer páginas rápidas.

O Google tem um vídeo bacana (em inglês) com algumas dicas para minimizar o reflow:

Dicas para manter suas páginas mais rápidas

  • Minimize o browser reflow
  • Reduza o HTML desnecessário do DOM e tente manter a árvore o mais "raza" possível. Quando uma alteração é feita em algum elemento ele causa efeitos em toda a árvode DOM, quando menos profunda ela for mais rápido será o reflow e qualquer outra manipulação no DOM.
  • Minimize o CSS e remova CSS que não é utilizado – o CSS é "interpretado" para formação da render tree, e o CSS "sobrando" sem dúvida vai tornar a render tree mais lenta, refletindo diretamente na experiência do usuário ao navegar nas suas páginas.
  • Para fazer animações e layouts mais complexos, sempre que possível faça isso fora do "reflow", para isso utilize posição absoluta ou fixed.
  • Evite seletores de CSS complexos, quanto mais profundo e complexo for um seletor mais custoso em performance será para mondar a render tree da página.

 

Como o browser renderiza sua página?

Para exemplificar melhor os assuntos que tratamos, abaixo tem um vídeo da Mozzilla, que mostra como o browser trabalha para renderizar uma página.

Não deixe de ver a apresentação sobre performance em javascript, outro fator muito importante quando falamos de performance no front-end.

Vamos fazer uma web mais rápida? 🙂

Referências:

Googl e code

Tableless

Switch no javascript

Este é um post muito básico sobre javascript, se você é ninja provavelmente não tem o que aprender com este post.

Switch é uma forma de fazer verificações diversas (do tipo "else if") em uma váriavel, estava criando um código que começou com uma verificação (um if) e com o tempo foi crescendo, quando percebi estava com 4 verificações if else até um colega me alertar para o uso do switch.

switch(n){
case 1:
  execute code block 1
  break;
case 'lorem':
  execute code block 2
  break;
default:
  code to be executed if n is different from case 1 and 2
}

Útil para quando você só precisa fazer comparação com uma única variável e mais performático que uma corrente de "if else".

Utilizando o cronômetro que o Chris postou aqui fiz um teste de performance no javascript comparando o switch e o if else (usando Firefox).

Código do teste de performance

function TimeCounter() {
this.startDate = null; this.ellapsedTime = null; this.start = function() { this.startDate = new Date(); } this.stop = function() { return (new Date() - this.startDate)/1000; } }

v = 0;
n = 'label';
var t = new TimeCounter();
t.start();
for(var i = 0;i < 1000000;i++){
switch(n){
case 'lorem':
v = v+1;
break;
case 2:
v = v+1;
break;
case 'llam':
v = v+1;
break;
case 'label':
v = v+1;
break;
default:
v = v+1;
}
}
i = t.stop();
console.log('Switch: ' + i);
v = 0;
t.start();
for(var i = 0;i < 1000000;i++){
if(n == 2){ v = v+1; }
else if(n == 'llam'){ v = v+1; }
else if(n == 'label'){ v = v+1; }
else{ v = v+1; } }
i = t.stop();
console.log('Else if: ' + i);

Resultados:

Switch: 4.345 s

Else if: 6.262 s

Sem querer levantar muito preciosimo para o código (vai só atrapalhar sua produtividade), fica aí a dica de fazer benchmark de código de suas aplicações quando estiver notando algum problema de performance, é uma boa forma de encontrar gargalos!

Lazy Load com jQuery [update]

Veja a página oficial do Lazy Load.

[changelog]

Saiu a nova versão do Lazy Load, veja o changelog completo da nova versão.

Visite o Github do projeto.

v1.0

  • Funciona sem classes
  • Otimização de performance – imagens já carregadas são arrancadas do array e não são mais percorridas

v0.5

  • Só funciona com seletor de classes nas imagens

Apliquei uma melhoria de performance no plugin (para não varrer repetidamente os elementos), ainda não consegui subir no Fiddle. Farei isso este final de semana e também vou documentar melhor o que ele faz para que mais pessoas possam contribuir com melhorias. 🙂

[/changelog]

 

Esta semana estava trabalhando em otimizações para a recém lançada home do iG e resolvemos aplicar o lazy load para melhorar ainda mais a experiência do usuário.

 

O que é Lazy Load?

Lazy load (ou "carregamento preguiçoso") é uma técnica de otimização de front-end que torna o carregamento inicial de uma página mais veloz inibindo o carregamento de imagens que não estão visíveis para o usuário.

Em páginas com uma altura grande e com uma quantidade alta de imagens razoável a técnica torna o carregamento muito mais veloz, e a medida que o usuário desce o scroll da página as imagens são carregadas para serem exibidas conforme a demanda.

A experiência do usuário é melhor pois a página é renderizada de forma mais rápidas, a fila de requisições é cortada portanto CSS e javascript são carregados e executados com menos tempo, e como acabei de ler As Leis da Simplicidade posso afirmar: reduzir tempo é um dos "processos de simplicidade" com o qual nós desenvolvedores devemos nos preocupar muito!

Mais um plugin de Lazy Load?

Tive a oportunidade de participar de todos os processos de desenvolvimento da nova home do iG e como estou pilhado em otimização nos últimos meses gostei muito da oportunidade de implementar otimizações após o lançamento. Dentre as otimizações aplicadas até agora uma das mais significativas no lado do usuário foi o Lazy Load.

Ps: até onde pesquisei o iG é o primeiro portal brasileiro a implementar a técnica 😀

Busquei diversas alternativas prontas e fiz vários testes, mas conclui que é impossível executar com sucesso o lazy load se o html for escrito com o link da imagem no atributo src.

os navegadores modernos (Chrome e Firefox, que consegui testar perfeitamente isso) na leitura inicial do DOM já identificam os links das imagens e adicionam na fila de requisições. Os plugins davam o efeito visual e até faziam uma nova requisição da imagem, sem nenhum efeito positivo para performance.

 

Plugin jQuery Lazy Load

A solução para realmente não carregar as imagens é não colocar o source da imagem no atributo src, para isso utilize uma imagem já carregada uma imagem transparente.

Para acessar a versão mais atualizada do plugin acess este fiddle.

jQuery Lazy Load

Adicione o plugin a sua página, necessita de jQuery (testado com v1.4.4)

/* lazyLoad */
(function($){
$.fn.lazyLoad = function() {
   var images = this,
       classe = this.selector.replace('.','');
   showVisible();
   $(window).scroll(function(){ showVisible(); })
   function showVisible(){
      images.each(function(){
         var img = $(this);
         if(img.hasClass(classe)){
            var imgTop = img.offset().top, wTop = $(window).scrollTop() + $(window).height() + 100;
            if(wTop > imgTop){ 
               img.removeClass(classe).attr('src', img.data('src')).fadeIn();
            } 
         }
      })
   }
};
})( jQuery );

Iniciando o plugin

Como a regra dos bons plugins manda, a inicialização do plugin é extremamente simples e o seletor deve ser uma classe que deve ser aplicada em todas as imagens que irão utilizar a técnica:

$('.lazy-load').lazyLoad();

 

O Html

O plugin utiliza o atributo data do HTML 5, portanto o HTML de todas as imagens que utilizam devem ficar da seguinte forma:

< img data-src="url-real-da-imagem" height="100" src="url-de-imagem-de-1px-transparente" width="100" / >

 

Testado em:

  • IE 7, 8, 9
  • Firefox
  • Chrome
  • Safari