otimização de desempenho em aplicações web e …§ão de desempenho em aplicações web e web...
TRANSCRIPT
UNIVERSIDADE FEDERAL DE SANTA CATARINA
Otimização de Desempenho em Aplicações Web e Web
Components
Diego Lagranha Weiss
Florianópolis – Santa Catarina
2015/1
UNIVERSIDADE FEDERAL DE SANTA CATARINA
CENTRO TECNOLÓGICO
DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA
CURSO DE CIÊNCIAS DA COMPUTAÇÃO
Otimização de Desempenho em Aplicações Web e Web
Components
Diego Lagranha Weiss
Trabalho de conclusão de curso
apresentado como parte dos requisitos
para obtenção do grau de Bacharel em
Ciências da Computação.
Florianópolis – Santa Catarina
2015/1
Diego Lagranha Weiss
Otimização de Desempenho em Aplicações Web e Web
Components
Este Trabalho de Conclusão de Curso foi julgado aprovado para a obtenção do Título de
“Bacharel em Ciências da Computação”, e aprovado em sua forma final pelo Curso de
Bacharelado em Ciências da Computação.
Florianópolis - Santa Catarina, Junho de 2015.
______________________________________________
Prof. Dr. Renato Cislaghi
Coordenador
Banca Examinadora:
______________________________________________
Prof. Dr. Frank Silveira
Orientador
______________________________________________
Prof. Dr. Leandro José Komosinski
______________________________________________
Prof. Dra. Patricia Della Mea Plentz
À minha família e amigos pela
compreensão da minha ausência.
Resumo
Originalmente pensadas para auxiliar o compartilhamento de informações entre
laboratórios, as páginas Web cresceram se tornaram aplicações completas no lado do
cliente, inclusive se tornaram um grande mecanismo para realização de negócios. A Amazon
concluiu que apenas 100 milissegundos de melhora aumentam 1% o seu faturamento
(LINDEN, 2008). O Yahoo! descobriu que para cada 400 milissegundos de melhora do
desempenho, seu tráfego aumenta em 9% (STEFANOV, 2008). Pessoas tendem a visitar
páginas que demonstram ser mais rápidas e que o tempo que esperam o carregamento é de
dois segundos ou menos (FORREST RESEARCH, 2009). Em geral, entre 80 e 90% do
tempo de resposta do usuário final é gasto no cliente (SOUDERS, 2007).
Nesse cenário, o foco da análise de desempenho no desenvolvimento Web recai
sobre conteúdo entregue ao cliente, e na forma como esse conteúdo é entregue. Esforços
para otimização resultam de forma imediata em impactos financeiros. O intuito desse
trabalho consiste em encontrar novas possibilidades de otimização, considerando também
novos recursos que ainda não foram explorados em relação ao seu desempenho, tentando
entender os gargalos e como contorná-los.
Entre as propostas apresentadas, a possibilidade de geração de código para um
navegador em específico apresentou melhoria no desempenho, tanto para o tempo de
carregamento quanto à execução da aplicação. Em Web Components, a pré-resolução de
HTML Imports e o pré-processamento de estilos do Shadow DOM garantiram redução no
tempo de carregamento de recursos e no tamanho dos recursos, respectivamente.
Palavras-chave: Otimização, desempenho, técnicas, Web, components, HTML, JavaScript,
CSS, HTTP, user-agent.
Lista de Figuras
Figura 1: Detalhamento de tempos de frontend e backend.....................................................17Figura 2: Modelo de rede de computadores cliente-servidor...................................................22Figura 3: Exemplo de uma requisição e resposta HTTP..........................................................24Figura 4: Árvore de objetos DOM do HTML.............................................................................28Figura 5: CSS no documento, externo e em linha....................................................................30Figura 6: Exemplo de código para a criação de um template..................................................32Figura 7: Exempo de herança em JavaScript e registro de um elemento customizado..........33Figura 8: DOM e subárvores.....................................................................................................34Figura 9: Exemplo de carregamento de arquivos de estilos e scripts......................................35Figura 10: Exemplo de carregamento de arquivos via HTML Imports.....................................36Figura 11: Aba principal do DevTools.......................................................................................41Figura 12: Aba Timeline do DevTools.......................................................................................42Figura 13: Página inicial do WebPageTest...............................................................................44Figura 14: Código CSS com propriedade background-image com fallback para demais navegadores..............................................................................................................................46Figura 15: Código CSS com propriedade background-image com suporte apenas ao WebKit....................................................................................................................................................46Figura 16: JavaScript que avalia em qual navegador o código está operando.......................46Figura 17: Resultado de desempenho entre as formas de se produzir laços de repetição no Chrome......................................................................................................................................48Figura 18: Resultado de desempenho entre as formas de se produzir laços de repetição no Firefox.......................................................................................................................................49Figura 19: Resultado de desempenho entre as formas de se produzir testes no Chrome......50Figura 20: Resultado de desempenho entre as formas de se produzir testes no Firefox.......50Figura 21: Resultados de desempenho entre as formas de se concatenar strings no Chrome....................................................................................................................................................50Figura 22: Resultados de desempenho entre as formas de se concatenar strings no Firefox....................................................................................................................................................51Figura 23: Resultado de desempenho entre as formas de se arredondar números no Chrome....................................................................................................................................................51Figura 24: Resultado de desempenho entre as formas de se arredondar números no Firefox....................................................................................................................................................52Figura 25: Declaração HTML que expressa uma condição para carregamento do CSS........53Figura 26: Documentos relacionados através de HTML Imports.............................................55Figura 27: Carregamento de componentes de forma bloqueante............................................55Figura 28: Carregamento de recursos com suporte cross-browser no Chrome......................59Figura 29: Carregamento dos recursos com suporte apenas ao Chrome...............................60Figura 30: Gráfico dos tempos gastos no carregamento e execução dos arquivos de suporte cross-browser no Chrome.........................................................................................................61Figura 31: Gráfico dos tempos gastos no carregamento e execução dos arquivos de suporte ao Chrome.................................................................................................................................61Figura 32: Carregamento de recursos com suporte cross-browser no Chrome......................62Figura 33: Carregamento dos recursos com suporte apenas ao Chrome...............................62Figura 34: Carregamento dos recursos com suporte ao Chrome e JavaScript otimizado......63
Figura 35: Gráfico dos tempos gastos no carregamento e execução dos arquivos com suporte ao Chrome e JavaScript otimizado..............................................................................64Figura 36: Carregamento dos recursos com suporte ao Chrome e JavaScript otimizado......64Figura 37: Relação entre a versão normal, formatada para o Chrome e a otimizada para o Chrome......................................................................................................................................65Figura 38: Componentes em linha no primeiro HTML..............................................................66Figura 39: Recursos dos componentes em linha no primeiro HTML.......................................66Figura 40: Carregamento de componentes de forma bloqueante............................................67Figura 41: Componentes em linha no primeiro HTML..............................................................67Figura 42: Recursos dos componentes em linha no primeiro HTML.......................................67Figura 43: Diferença entre HTML Imports e seus recursos ou código em linha......................68Figura 44: Exemplo de estilo para um componente de teste do Shadow DOM......................69Figura 45: Estilo do componente pós otimização.....................................................................69Figura 46: Carregamento de 12 componentes em uma aplicação com Shadow DOM...........69Figura 47: Estilo do HTML pós otimização...............................................................................70Figura 48: Carregamento de 12 componentes em uma aplicação com Shadow DOM otimizado...................................................................................................................................70Figura 49: Aplicação com Shadow DOM..................................................................................71Figura 50: Aplicação com Shadow DOM otimizado.................................................................71Figura 51: Diferença entre a aplicação com Shadow DOM otimizado e não otimizado..........72Figura 52: Resultado de desempenho entre as formas de se aplicar/modificar propriedades CSS no Chrome........................................................................................................................81Figura 53: Resultado de desempenho entre as formas de se aplicar/modificar propriedades CSS no Chrome........................................................................................................................82Figura 54: Resultado de desempenho entre as formas de se aplicar/modificar propriedades CSS entre versões do Chrome e Firefox..................................................................................83Figura 55: Resultado de desempenho entre as formas de se exibir e esconder um elemento HTML no Chrome......................................................................................................................84Figura 56: Resultado de desempenho entre as formas de se aplicar/modificar propriedades CSS no Firefox..........................................................................................................................84Figura 57: Resultados dos testes de desempenho de seletores CSS.....................................86
Lista de Abreviações e Siglas
WWW – World Wide Web
HTML – HyperText Markup Language
HTTP – Hypertext Transfer Protocol
CSS – Cascading Style Sheets
DOM – Document Object Model
JSON – Java Script Object Notation
TCP – Transmission Control Protocol
UDI – Uniform Driver Interface
URL – Uniform Resource Locator
URI – Uniform Resource Identifier
CERN – Organização Europeia para a Pesquisa Nuclear
CGI – Common Gateway Interface
IP – Internet Protocol
DNS – Domain Name System
API – Application Programming Interface
AJAX – Asynchronous JavaScript and XML
W3C – World Wide Web Consortium
WHATWG – Web Hypertext Application Technology Working Group
Sumário
RESUMO..........................................................................................................................................................6
LISTA DE FIGURAS........................................................................................................................................7
LISTA DE ABREVIAÇÕES E SIGLAS............................................................................................................9
SUMÁRIO......................................................................................................................................................10
1. INTRODUÇÃO...........................................................................................................................................12
1.1 Problema.............................................................................................................................12
1.2 Objetivo...............................................................................................................................15
1.3 Justificativa..........................................................................................................................15
1.4 Metodologia de trabalho.....................................................................................................17
1.5 Organização do texto..........................................................................................................18
2. CONCEITOS FUNDAMENTAIS................................................................................................................19
2.1.1 Origem.............................................................................................................................19
2.1.2 Modelo Cliente-Servidor................................................................................................20
2.1.3 HTTP................................................................................................................................22
2.1.4 HTML...............................................................................................................................25
2.1.5 DOM.................................................................................................................................26
2.1.6 JavaScript.......................................................................................................................27
2.1.7 CSS..................................................................................................................................28
2.2 Web Components...............................................................................................................29
2.2.1 Templates........................................................................................................................30
2.2.2 Custom Elements...........................................................................................................31
2.2.3 Shadow DOM..................................................................................................................33
2.2.4 Imports............................................................................................................................34
3. DESEMPENHO..........................................................................................................................................36
3.1 Técnicas de otimização.......................................................................................................36
3.2 Ferramentas........................................................................................................................39
3.2.1. JSPerf.............................................................................................................................40
3.2.2 Google DevTools............................................................................................................40
3.2.3 WebPageTest..................................................................................................................42
4. PROPOSTAS DE OTIMIZAÇÃO...............................................................................................................44
4.1 Código específico................................................................................................................44
4.2 JavaScript otimizado...........................................................................................................45
4.3 CSS otimizado....................................................................................................................52
4.4 HTML otimizado..................................................................................................................52
4.5 Web Components...............................................................................................................53
4.5.1 HTML Imports.................................................................................................................53
4.5.2 Shadow DOM..................................................................................................................55
5. RESULTADOS...........................................................................................................................................57
5.1 Código específico................................................................................................................57
5.2 JavaScript otimizado...........................................................................................................61
5.3 HTML Imports......................................................................................................................64
5.4 Shadow DOM......................................................................................................................67
6. CONCLUSÃO............................................................................................................................................72
6.1 Trabalhos futuros................................................................................................................72
BIBLIOGRAFIA.............................................................................................................................................74
APÊNDICE A.................................................................................................................................................76
ANEXO I - ARTIGO.......................................................................................................................................82
ANEXO II - CÓDIGO......................................................................................................................................91
1. Introdução
Originalmente a World Wide Web - em português, Grande Teia Mundial, ou
apenas Web, foi concebida em 1989 como um sistema de informação para melhor gerenciar
as informações produzidas no laboratório CERN (Organização Européia para a Pesquisa
Nuclear) (BERNERS-LEE, 1989). Desenvolvimentos mais recentes desta tecnologia têm
permitido distribuir, junto às informações, objetos e programas que realizam atividades no
cliente consumidor da informação. Também tem permitido o desenvolvimento de aplicações
orientadas a componentes junto ao cliente. Nesse contexto identifico os possíveis gargalos,
apresento as técnicas existentes e proponho modificações com intuito de otimizar o seu
tempo de carregamento e de execução.
1.1 Problema
A forma de desenvolver na Web mudou bastante nos últimos 25 anos. Como o
projeto inicial não era inerentemente dinâmico, no início hipertexto1 consistia em HTML
codificado “na mão” que era publicado em servidores Web. Quaisquer modificações
necessárias em páginas publicadas tinham que ser feitas pelo autor das páginas. Para
fornecer uma página Web dinâmica que refletia as entradas do usuário, conectando
aplicações externas com servidores Web, em 1997 surgiu o padrão CGI (Common Gateway
Interface) (RFC 3875). Na mesma época, ambientes de desenvolvimento integrado
servidor/linguagem surgiram pela primeira vez, como WebBase e novas linguagens
especificamente para uso na Web começaram a surgir, tais como ColdFusion, PHP e Active
Server Pages. No lado do cliente, as tecnologias predominantes consistem em HTML para
1 Hipertexto é uma maneira de conectar e acessar informações de vários tipos, como uma teia de nós no qual o usuáriopode navegar livremente.
estruturar um documento, CSS para estilizar os elementos nesse documento e JavaScript
para adicionar comportamento. Quando os navegadores implementaram tabelas (elemento
HTML <table>) no Netscape Navigator 1.1 e IE 2.0 em 1995 e 1996 ainda não se falava em
acessibilidade e semântica, que apareceriam a partir de 1997 com o HTML 3.2 (W3C, 1997).
A Web estava sendo criada e utilizada ao mesmo tempo, onde assim como hoje, as
implementações apareciam antes de se ter uma especificação concluída.
Fazia-se praticamente tudo no lado do servidor e o problema de reuso de
componentes de software estava praticamente resolvido com adoção de técnologias como
Rails ou templates de Django. Por conta do aumento do poder de processamento do cliente
o cenário mudou. De motores JavaScript de melhor desempenho, passou-se a um maior
número de aplicações mistas, onde delega-se muita lógica para o cliente. Ao invés de
devolver blocos prontos de HTML, agora devolve-se dados semi-estruturados em JSON
(Java Script Object Notation) e então o JavaScript criar os elementos no DOM.
Existem organismos que definem como devem ser as linguagens HTML, CSS e
JavaScript. Porém, às vezes, as interpretações são distintas por parte das empresas
desenvolvedoras de navegadores, que se permitem a criar novas etiquetas ou
funcionalidades, inclusive decidir quais suportar. À medida que os navegadores evoluem, as
especificações também melhoram, por isso diferentes versões do mesmo navegador podem
apresentar páginas HTML de maneira diferente entre si.
Web Components (W3C, 2014) é um conjunto de especificações (Custom
Elements, Shadow DOM, Templates, HTML Imports), influenciadas por frameworks2 e
bibliotecas JavaScript, que auxiliam o desenvolvedor a escrever páginas HTML baseadas em
componentes (dando ao código uma melhor semântica e uma melhor manutenibilidade),
padronizando as suas principais funcionalidades. Desse modo, Web Components auxiliam o
2 Uma abstração que une códigos comuns entre vários projetos de software provendo uma funcionalidade genérica.
desempenho, implementando no navegador recursos que só estariam disponíveis através de
carregamentos externos. No entanto, foi necessário identificar gargalos dessas
especificações com o intuito de propor técnicas que coibem a perda de desempenho.
O impacto no desempenho pode ser aferido de diversas maneiras em aplicações
Web. Como um sistema distribuído, pode-se aferir o tempo de carregamento de recursos e a
ordem como são carregados, sendo que esse tempo está em função da taxa de transmissão
do cliente e o tamanho do recurso solicitado. O bloqueio de conteúdo gráfico em páginas
Web pode trazer uma sensação de lentidão maior, prejudicando a experiência do usuário.
Executar código JavaScript pode também produzir diferentes resultados de desempenho em
navegadores distintos. O mesmo ocorre com a renderização dos elementos HTML. Isso
acontece por conta da diferença entre implementações dos navegadores e de seus motores
gráficos e de JavaScript.
Os desenvolvedores da Web têm que lidar com todas essas questões, pois os
programas com os quais o público visualizará o conteúdo podem ser muito diferentes. Além
do mais, o desempenho do conteúdo entregue ao cliente se tornou mais crítico, uma vez que
passou a representar o maior tempo da aplicação (SOUDERS, 2007). Aplicações cross-
browser (aquelas capazes de suportar múltiplos navegadores), que representam uma
solução para lidar com as diferentes implementações de navegadores, em geral requerem a
entrega de mais conteúdo ao cliente, aumentando, por conseguinte, o tempo de
carregamento da aplicação.
1.2 Objetivo
O objetivo desse trabalho consiste em apresentar e avaliar propostas que
otimizem o tempo de carregamento de aplicações Web, sejam elas aplicações simples,
cross-browser e/ou consumidoras de Web Components. Propostas não necessariamente
caracterizadas como técnicas de programação, mas muito mais como algoritmos a serem
implementados em ferramentas de pré-processamento de recursos. Para isso, faz-se
necessário primeiro detalhar a estrutura de uma aplicação Web e identificar os seus
possíveis gargalos de desempenho.
1.3 Justificativa
Um estudo realizado pela empresa independente de pesquisa Forrest Research
em 2009 (FORREST RESEARCH, 2009), comprova a teoria de que pessoas tendem a visitar
páginas que demonstram ser mais rápidas e que o tempo que esperam o carregamento é de
dois segundos ou menos. Entre três e quatro segundos temos um usuário insatisfeito, em 5
segundos ou mais eles tendem a simplesmente abandonar a página. O Yahoo!, descobriu
que, para cada 400 milissegundos de melhora na performance, seu tráfego aumenta em 9%
(STEFANOV, 2008). A Mozilla, ao reduzir 2,2 segundos da landing page3 do Firefox
aumentou o número de downloads em 15% (CUTLER, 2010), totalizando um ganho de mais
de 60 milhões de cópias por ano. A Amazon concluiu que apenas 100 milissegundos de
melhora aumentam 1% o seu faturamento (LINDEN, 2008). Em um de seus vários
experimentos, o Google aumentou o número de resultados por página de 10 para 30
(LINDEN, 2006). Isso aumentou o tempo de carregamento de 0.4 segundos para 0.9, o que
diminuiu em 20% o tráfego das buscas. A Microsoft mostrou que 2 segundos a mais de
latência no Bing diminuíam o faturamento em 4,3% (SCHURMAN, 2009). Há diversos outros
experimentos publicados, incluindo um estudo que mostra uma relação entre sites lentos e
queda da pressão arterial (SCHEIRER, 2002). Steven Souders, uma das autoridades em3 Página de destino ou página de entrada, é a página por onde o visitante chega a um site, quando um usuário clica em um
resultado de busca ou em um anúncio de banner ou links patrocinados, eles são direcionados para as landing pages.
desempenho Web, destaca o que ele nomeia como regra de ouro do desempenho: “80-90%
do tempo de resposta do usuário final é gasto no cliente” (SOUDERS, 2007).
A figura 1 exibe um gráfico waterfall onde o tempo do servidor é o tempo para
obter o retorno do primeiro byte para o cliente. Nela, cada linha representa um recurso
solicitado ao servidor e o seu tempo de carregamento. Isso normalmente inclui a maior parte
do processamento no servidor: pesquisas de banco de dados, chamadas de serviços
remotos da Web, entre outras. O tempo de cliente é todo o resto, incluindo as fases de
execução de JavaScript e de renderização da página. Também inclui o tempo de
Figura 1: Detalhamento de tempos de frontend e backend.
Fonte: Steve Souders - The Performance Golden Rule.
comunicação através da rede para carregar todos os recursos referenciados na página.
Considerando então o cliente como o maior tempo da aplicação, somado ao
impacto financeiro correspondente ao desempenho das aplicações Web, torna-se nítida a
importância do desenvolvimento de técnicas que otimizem o seu tempo de carregamento e
execução.
1.4 Metodologia de trabalho
No primeiro momento é realizado um estudo sobre as tecnologias que
fundamentam as aplicações Web, seguido dos fatores que influenciam o seu desempenho.
Também é empreendido um estudo sobre as técnicas de otimização já empregadas e de
ferramentas que auxiliam sua utilização. Dentro desse contexto, apresento testes
implementados que avaliam o desempenho entre navegadores distintos.
Para atingir o objetivo são exploradas as diferenças com que navegadores
executam recursos e aplicados os princípios de otimização em sistemas distribuídos. É então
cronometrado o carregamento e execução dos cenários de teste, avaliando o ganho ou não
de desempenho. O êxito da pesquisa se dá em um carregamento e execução em tempo
inferior ao registrado da aplicação não otimizada.
1.5 Organização do texto
Este trabalho está organizado em mais 5 capítulos. O capítulo 2 visa apresentar
os conceitos fundamentais explorados nesse projeto, dando uma visão geral das tecnologias
que fundamentam a Web. O capítulo 3 descreve as principais técnicas de otimização
empregadas atualmente. Também apresenta ferramentas que auxiliam a depuração e
avaliação do desempenho. No capítulo 4 são descritas as propostas de otimizações
sugeridas pelo autor. O capítulo 5 apresenta os resultados dos testes das otimizações
propostas. Finalmente, o capítulo 6 expõe as conclusões da pesquisa e apresenta os
possíveis trabalhos futuros derivados desse estudo.
2. Conceitos fundamentais
A Web é um sistema de informação baseado em documentos de hipertexto
interligados construído sobre a infra-estrutura de comunicação provida pela Internet. Páginas
de documentos individuais na World Wide Web são chamados de páginas Web e são
acessadas através de um software aplicativo conhecido por navegador Web. As páginas da
Web podem conter texto, imagens, vídeos e outros componentes multimídia, bem como
recursos de navegação que consistem em hiperlinks.
2.1 Web
2.1.1 Origem
A Web foi proposta pelo físico e cientista da computação britânico Timothy John
Berners-Lee em 1989 (BERNERS-LEE, 1989), inicialmente com objetivo de melhorar a
gestão de informações gerais sobre aceleradores e experiências no laboratório onde
trabalhava, CERN. Inspirado no ENQUIRE, um projeto de software e banco de dados que ele
havia construído em 1980, descrito como um sistema de gerenciamento de informação mais
elaborado com base em links embutidos no texto legível. No final do ano de 1990, com a
ajuda de Robert Cailliau, Berners-Lee publicou uma proposta mais formal para a World Wide
Web (BERNERS-LEE, CAILLIAU, 1990). Utilizando um computador NeXTcube, ainda no
mesmo ano, Berners-Lee já havia construído todas as ferramentas necessárias para o
funcionamento do sistema especificado no projeto: o primeiro navegador, o WorldWideWeb,
o primeiro servidor e as primeiras páginas Web. Em 6 de agosto de 1991, ele publicou um
pequeno resumo do projeto World Wide Web no grupo de notícias alt.hypertext. Esta data
também marcou a estréia da Web como um serviço disponível ao público na Internet.
No processo, Berners-Lee desenvolveu três tecnologias essenciais:
• Um sistema de identificadores únicos globais para recursos na Web e em outros
lugares, o Identificador de Documento Universal (UDI), mais tarde conhecido como
Localizador Uniforme de Recurso (URL) e Identificador Uniforme de Recursos (URI);
• O idioma de publicação HyperText Markup Language (HTML);
• E o Hypertext Transfer Protocol (HTTP).
Conectados pela Internet existente, outros sites foram criados em torno do mundo,
empregando os padrões internacionais para nomes de domínio e HTML. A World Wide Web
permitiu a disseminação de informações através da Internet empregando um formato fácil de
usar e flexível, tendo assim um papel importante na popularização uso da Internet.
2.1.2 Modelo Cliente-Servidor
O modelo cliente-servidor descreve a relação entre programas numa aplicação. O
componente de servidor fornece uma função ou serviço a um ou mais clientes, que iniciam
os pedidos de serviço, como mostra a figura 2. Este é o modelo predominante na Web onde
a exibição de uma página normalmente começa quando o usuário digita uma URL em um
navegador, ou segue um hiperlink para a página ou recurso. O navegador, em seguida, inicia
uma série de mensagens de comunicação para buscar e exibir a página solicitada. O
navegador resolve o nome do servidor do URL (por exemplo, www.ufsc.br) em um endereço
IP (Internet Protocol) utilizando o DNS (Domain Name System) (RFC 1035). Essa pesquisa
retorna um endereço IP (por exemplo, 150.162.2.10). O navegador, em seguida, solicita o
recurso através do envio de uma solicitação HTTP através da Internet para o computador
nesse endereço. Ele solicita um serviço a um número de porta TCP (Transmission Control
Protocol) específica que é conhecido para o serviço HTTP. O computador que recebe o
pedido HTTP, entrega-o ao software do servidor Web, que fica constantemente ouvindo por
solicitações na porta 80. Então o servidor Web envia uma resposta HTTP ao navegador
indicando o sucesso, seguido pelo conteúdo da página solicitada.
O navegador então analisa o HTML e interpreta a marcação (<title> para título,
<p> para o parágrafo, etc) que envolve as palavras a fim de formatar o texto na tela. Muitas
páginas da Web utilizam HTML para referenciar as URLs de outros recursos, como imagens,
outros meios de comunicação integrados, os scripts que afetam o comportamento da página
e CSS (Cascading Style Sheets) que afetam o layout da página. O navegador faz
solicitações HTTP adicionais para o servidor Web para esses outros tipos de mídia Internet.
Como ele recebe o seu conteúdo a partir do servidor, o navegador processa
progressivamente a página na tela, tal como especificado pelo seu HTML e esses recursos
adicionais.
Figura 2: Modelo de rede de computadores cliente-servidor.
2.1.3 HTTP
HTTP é um protocolo de aplicação responsável pelo tratamento de pedidos e
respostas entre cliente e servidor com o intuito de viabilizar a distribuição de informações
pela Internet. Em sua primeira versão, a chamada HTTP/0.9 (W3C, 1991), o protocolo tinha
apenas um método, o GET, que requisita uma página para o servidor. A partir da versão
HTTP/1.0 (RFC 1945), desenvolvida entre 1992 e 1996, foi dado também suporte a outros
tipos de arquivos (do tipo MIME33 - Multipurpose Internet Mail Extension) e implementados
novos métodos de requisição chamados HEAD e POST. Já na versão atual, a HTTP/1.1
(RFC 2616), fora desenvolvido novas funcionalidades como por exemplo conexões
persistentes, novos métodos de requisições, uso de servidores proxy para permitir melhor
organização do cache4, entre outros. Em 18 de fevereiro 2015, uma nova versão do
protocolo, o HTTP/2.0 (RFC 7540), foi aprovada. A sintaxe é basicamente a mesma do
HTTP/1.1, entretanto, o elemento modificado é a forma como os dados são encapsulados e
transportados entre o cliente e o servidor, minimizando o tempo de carregamento. No
entanto, otimizações que visam diminuir o número de requisições e o conteúdo entregue ao
cliente continuam válidas.
Um exemplo de requisição HTTP é apresentado na figura 3. Segundo seu
cabeçalho, enviamos qual o método da requisição e algumas informações que identificam
nosso cliente. O servidor, por sua vez, identifica os cabeçalhos que lhe são convenientes e
envia uma resposta.
Nos cabeçalhos de resposta obtem-se algumas informações importantes, dentre
elas o código de resposta (Status-Code). Este código identifica se uma requisição foi
concluída com sucesso (200) ou se ela não existe (404), por exemplo.4 Dispositivo de acesso rápido, interno a um sistema, que serve de intermediário entre um operador de um processo e o
dispositivo de armazenamento ao qual esse operador acede.
Negociação de conteúdo
Infelizmente para os servidores nem todos os clientes têm a mesmas preferências
do que seja “melhor” e nem todos são igualmente capazes de renderizar todos os tipos de
entidade. Por essa razão, HTTP tem provisões para vários mecanismos de “negociação de
conteúdo” - mecanismo utilizado quando é necessário servir diversos conteúdos equivalentes
para um determinado URI, a fim de fornecer o conteúdo mais adequado para o usuário final.
A determinação do teor de melhor adequado é feita através de um dos três mecanismos:
• Cabeçalhos HTTP específicos pelo cliente (de negociação orientada por servidor);
Figura 3: Exemplo de uma requisição e resposta HTTP.
• Pelo código de resposta de redirecionamento 300 (Multiple choices) do HTTP e código
de resposta de erro do cliente 406 (Not Acceptable) (de negociação orientada por
agente);
• Cache (negociação transparente).
Na negociação orientada por servidor, o navegador (ou qualquer outro tipo de
agente) envia vários cabeçalhos HTTP, juntamente com a URI. Estes cabeçalhos descrevem
a escolha preferida do utilizador. O servidor usa-os como sugestões em um algoritmo interno
a fim de escolher o melhor conteúdo para servir ao cliente. O HTTP/1.1 padrão dá uma lista
de cabeçalhos padrão que podem ser utilizados em um algoritmo de negociação orientada
por servidor (Accept:, Accept-Charset:, Accept-Encoding:, Accept-Language: e User-Agent:).
No entanto, é permitido ao servidor utilizar outros aspectos em seu algoritmo, mesmo
aspectos externos à própria solicitação ou campos de cabeçalho de extensão, ou seja,
cabeçalhos não definidos no HTTP/1.1 padrão. A utilização de negociação de conteúdo
orientada por servidor altera as condições e o processo pelo qual um cache pode usar a
resposta para solicitações subsequentes. O servidor deve utilizar o cabeçalho Vary para
informar um cache de quais campos de cabeçalho da solicitação foram utilizados para
selecionar entre várias representações de uma resposta “cacheável”. É utilizando esse tipo
de negociação que elaboro uma das propostas de otimização no capítulo 4.
A negociação orientada por agente, a escolha da melhor representação para uma
resposta é realizada pelo agente após o recebimento da resposta. A seleção é baseada em
uma lista das representações disponíveis na resposta incluídos nos campos de cabeçalho. A
negociação transparente é uma combinação das duas negociações.
2.1.4 HTML
O HTML é uma linguagem de marcação de hipertexto. Hipertextos são conjuntos
de elementos interligados através de hyperlinks5, podendo esses elementos ser palavras,
imagens, vídeos, áudio, documentos, etc, que conectados formam uma grande rede de
informação. Propõe-se a ser uma linguagem que seja entendida universalmente no sentido
de que a informação publicada por meio deste código possa ser acessível por dispositivos e
outros meios com características diferentes. Fornece um meio para criar documentos
estruturados denotando uma semântica estrutural para o texto como cabeçalhos, parágrafos,
listas, links, citações e outros itens. É possível incorporar scripts em linguagens como
JavaScript que podem modificar o comportamento das páginas Web. Uma página também
pode se referir a estilos definidos em arquivos CSSs para definir a aparência e o layout de
texto e outros elementos.
A primeira descrição disponível publicamente do HTML foi um documento
chamado de "tags HTML", mencionado na Internet por Berners-Lee, no final de 1991
(BERNERS-LEE, 1991). A versão atual, HTML5 (W3C, 2014) teve como principal objetivo
facilitar a manipulação dos elementos HTML, permitindo o desenvolvedor modificar as
características dos objetos de forma não intrusiva e de maneira que seja transparente ao
usuário final. Ao contrário das versões anteriores, o HTML5 fornece ferramentas para a CSS
e o JavaScript fazerem seu trabalho da melhor maneira possível. O HTML5 também cria
novas tags e modifica a função de outras. As versões antigas do HTML não continham um
padrão universal para a criação de seções comuns e específicas como rodapé, cabeçalho,
sidebar, menus. Não havia um padrão de nomenclatura de IDs, classes ou tags. Tampouco
um método para capturar de maneira automática as informações localizadas nos rodapés de5 Nome que se dá às imagens ou palavras que dão acesso a outros conteúdos em um documento hipertexto. O hyperlink
pode levar a outra parte do mesmo documento ou a outros documentos.
sites. Há outros elementos e atributos que tiveram sua função e significado modificados e
que agora podem ser reutilizados de forma mais eficaz. Propõe mais semântica com menos
código, mais interatividade sem a necessidade de instalação de plugins e perda de
desempenho.
2.1.5 DOM
O DOM (Document Object Model) é uma convenção multiplataforma e
independente de linguagem para representar e interagir com objetos em HTML, XHTML, e
documentos XML. Os nós de todos os documentos são organizados em uma estrutura de
árvore, chamada de árvore DOM, como representada na figura 4. Objetos na árvore DOM
podem ser endereçados e manipulados utilizando métodos nos objetos. A interface pública
de um DOM é especificada na sua API (Application Programming Interface).
A história do DOM está intimamente ligada com o início das linguagens de script.
Após o lançamento do ECMAScript (explicado no capítulo sobre JavaScript) a W3C começou
a trabalhar na padronização do DOM. O padrão inicial, conhecido como "DOM Nível 1", foi
recomendado no final de 1998 (W3C, 1998). Na mesma época, o Internet Explorer 5.0 foi
entregue com suporte limitado para DOM Nível 1. DOM Nível 1 proveu desde um modelo
completo para um documento HTML como para um XML, incluindo meios para modificar
qualquer parte deste. Navegadores não conformes, tais como Internet Explorer e Netscape
4.x 4.x ainda foram amplamente utilizados até o ano 2000. DOM Nível 2, publicado no final
de 2000 (W3C, 2000), introduziu a função "getElementById", bem como um modelo de
evento e suporte para namespaces XML e CSS. No DOM Nível 3, a versão atual da
especificação do DOM (W3C, 2004), adicionou suporte para XPath e manipulação de
eventos de teclado, bem como uma interface para a serialização de documentos XML.
2.1.6 JavaScript
Também conhecido como ECMAScript, é uma linguagem de programação
dinâmica, mais comumente utilizada em navegadores Web, projetada inicialmente com
intuito de permitir que os scripts do lado do cliente pudessem interagir com o usuário,
controlar o navegador, comunicar de forma assíncrona com o servidor e alterar o conteúdo
do documento exibido. A Netscape introduziu uma implementação da linguagem de script do
servidor com o Netscape Enterprise Server em dezembro de 1994, logo depois de lançar o
JavaScript para navegadores. Mas que por questões de desempenho não houve tanta
adesão.
Com o advento do AJAX (Asynchronous JavaScript and XML), JavaScript recebeu
mais atenção profissional. O resultado foi a proliferação de frameworks e bibliotecas, práticas
de programação melhoradas e o aumento no uso do JavaScript fora do ambiente de
Figura 4: Árvore de objetos DOM do HTML.
navegadores. Em 2008 a Mozilla anunciou o TraceMonkey, o primeiro compilador just-in-
time6 escrito para a linguagem JavaScript. Seguido da Google com seu interpretador V8, com
a mesma proposta de acelerar o desempenho compilando o código JavaScript para o
formato de máquina antes de executá-lo, permitindo que executasse em velocidade de
código binário compilado. Isso permitiu o ressurgimento de implementações JavaScript do
lado do servidor, como por exemplo o Node.js7.
2.1.7 CSS
CSS é uma linguagem de folha de estilo utilizada para descrever a aparência e a
formatação de um documento escrito em uma linguagem de marcação. Foi proposta pela
primeira vez por Hakon Wium Lie, em 10 de outubro de 1994 (HAKON, 1994). Na época, Lie
trabalhava com Berners-Lee no CERN. Embora na maioria das vezes utilizada para alterar o
estilo de páginas Web e interfaces de utilizador escritas em HTML e XHTML, a linguagem
pode ser aplicada a qualquer tipo de documento XML. Junto com HTML e JavaScript, CSS é
uma tecnologia fundamental utilizada pela maioria dos sites para criar páginas Web
visualmente atraentes e interfaces de usuário para muitas aplicações móveis.
Os estilos podem ser incorporados no documento HTML de três maneiras
diferentes: estilo no documento, declarado no cabeçalho, quer dizer, entre as tags <head> e
</head>; em linha, como atributo das tags; e externo, declarado num arquivo à parte cuja
extensão é .css. O trecho de código da figura 5 apresenta um exemplo de como incorporar
CSS das três formas citadas.
6 Também conhecida como tradução dinâmica, é a compilação de um programa em tempo de execução, utilizando uma abordagem diferente da compilação anterior à execução.
7 http://nodejs.org/
Com a popularidade do HTML, passou-se a abranger uma ampla variedade de
recursos estilísticos para atender às demandas dos desenvolvedores Web. Esta evolução
deu ao designer mais controle sobre a aparência do site, ao custo de um HTML mais
complexo. Variações em implementações de navegadores fez a consistência na aparência
de sites difícil e códigos cross-browser proliferarem.
2.2 Web Components
Web Components é um conjunto de especificações (W3C, 2014) projetadas para
serem utilizadas juntas. Objetivam auxiliar desenvolvedores Web com aumento de reuso,
encapsulamento e modularidade do seu código, através de APIs nativas (implementadas no
navegador), que disponibilizam recursos que só estariam disponíveis com a utilização de
frameworks e bibliotecas JavaScript, carregados externamente. Web Components é hoje um
conjunto de 4 especificações:
• Templates, que definem pedaços de marcação que são inertes, mas podem ser
Figura 5: CSS no documento, externo e em linha.
ativados para uso posterior;
• Custom Elements, que permite que autores definam seus próprios elementos, com
novos nomes de tag HTML e nova interface de script;
• Shadow DOM, o qual encapsula uma subárvore DOM para uma composição mais
confiável dos elementos de interface do usuário;
• Imports, que define como Templates e Custom Elements serão empacotados e
carregados como um recurso.
Essas especificações são individualmente úteis, mas se tornam muito mais
importantes quando combinadas. Dessa maneira o desenvolvedor consegue criar um
componente funcional, com visual e código customizados, encapsulando lógica, estilo e
semântica.
2.2.1 Templates
O conceito de template não é novo para o desenvolvimento Web. Linguagens de
templates do lado do servidor/motores como Django (Python), ERB/Haml (Ruby), e Smarty
(PHP) existem há muito tempo. Nos últimos anos, porém, temos visto surgir uma explosão de
frameworks e bibliotecas no cliente, na tentativa de organizar esse código. Todos um pouco
diferentes, mas a maioria compartilha um motor comum para renderização em sua camada
de apresentação, no caso, templates.
Template é um documento ou arquivo que tem um formato predefinido, de modo
que o formato não tem de ser recriado cada vez que é utilizado. O conteúdo do elemento
<template> é analisado pelo analisador HTML, mas é inerte: os scripts não são processados,
as imagens não são carregadas, e assim por diante. O elemento <template> tem uma
propriedade content (conteúdo) que representa o conteúdo do modelo em um fragmento de
documento. Quando o autor deseja utilizar o conteúdo, ele pode mover ou copiar os nós a
partir desta propriedade e aí sim os scripts são executados e as imagens são carregadas. A
figura 6 exemplifica o uso desse elemento.
2.2.2 Custom Elements
Tags ou etiquetas são estruturas de linguagem de marcação contendo instruções,
tendo uma marca de início e outra de fim, para que o navegador possa renderizar o conteúdo
daquele elemento com uma semântica específica. As tags são as responsáveis por definir a
aparência e/ou comportamento da página. Por exemplo, no cabeçalho <head> pode-se
encontrar outras etiquetas referentes à formatação do estilo, scripts que podem definir
comportamentos do documento e meta informações. No corpo é possível encontrar outras
tags que irão determinar o conteúdo da página, como por exemplo <h1>, <h2>, ... <h6>, que
definem cabeçalhos e títulos no documento, <p> para um novo parágrafo, <div> que cria
uma divisão na página. Existem muitas outras tags no HTML, mesmo assim não é possível
Figura 6: Exemplo de código para a criação de um template.
suprir todas as necessidades dos desenvolvedores de aplicações Web. Por conta disso, o
código para construir um layout8, utilizando os elementos existentes do HTML, acaba se
tornando um emaranhado de estruturas como listas, divs, parágrafos, títulos. Uma solução
proposta por essa especificação é possibilitar o autor à criação de suas próprias tags, que
irão definir elementos HTML chamados de elementos customizados ou originalmente
Custom Elements.
O argumento do document.registerElement() define o nome do elemento
customizado, ou seja, da nova tag. Para que um elemento seja realmente um elemento, além
de registrá-lo no navegador, requer-se que ele herde as características de funcionamento
que o JavaScript tem sobre um elemento HTML convencional. Para isso, cria-se um objeto
JavaScript que herda as características do elemento HTML e o prototype JavaScript, como
mostra a figura 7.
2.2.3 Shadow DOM
Pela especificação, Shadow DOM é uma árvore adjunta dos nodos do DOM. Esta
subárvore pode ser associada a um elemento, mas não aparece como um nodo filho do
elemento. Ao invés disso a subárvore define seu próprio escopo. Por exemplo, uma
subárvore Shadow DOM pode conter IDs e estilos que sobrepõem IDs e estilos do
documento, mas visto que a subárvore Shadow DOM (diferente de uma lista de nodo filho) é
separada do documento, os IDs e estilos na subárvore do Shadow DOM não conflitam com8 Tem como seus componentes a área de design ou formato de página e suas margens.
Figura 7: Exempo de herança em JavaScript e registro de um elemento customizado.
os do documento. A figura 8 exemplifica a estrutura do Shadow DOM.
Uma das grandes razões para a implementação da Shadow DOM pelos
navegadores é a possibilidade de manter seus componentes inalteráveis, isolando-os de
todo tipo de acesso – ou seja, mantendo tudo dentro de uma espécie de caixa preta.
Componentes de interface que são utilizados em aplicações HTML como <select> e <input>
dos tipos text, range, number, color, datetime não passam de elementos HTML estilizados
com CSS de acordo com o estilo de cada navegador. A grande diferença na verdade é o
encapsulamento. Não temos acesso a esses elementos internos do componente, assim não
é possível manipulá-los, nem modificar o seu estilo.
Figura 8: DOM e subárvores.
Fonte: W3C
2.2.4 Imports
Ainda definindo Web Components como um conjunto de HTML, CSS, JavaScript
que funciona em independência e isolamento, o que resta é o problema de como
"empacotar" esse conjunto de recursos. É onde entra a especificação HTML Imports, que na
prática nada mais é do que um arquivo HTML contendo links para outros arquivos como
folhas de estilo (CSS), imagens, JavaScript e outros recursos. Atualmente, para carregar um
conjunto de folhas de estilo ou scripts, precisa-se declarar manualmente sua URL, como
mostra a figura 9.
O carregamento de recursos através de HTML Imports pode-se resumir ao código
da figura 10.
Figura 9: Exemplo de carregamento de arquivos de estilos e scripts.
Figura 10: Exemplo de carregamento de arquivos via HTML Imports.
3. Desempenho
O desempenho tornou-se um importante fator para o sucesso de aplicações Web.
Não somento no aspecto comercial, como também no impacto no contexto social, como a
educação, entretenimento e muitas outras áreas que se utilizam das facilidades da Web para
alcançar seu público. Desempenho Web é tema de dois livros de Steve Souders: High
Performance Web Sites (SOUDERS, 2007) e Even Faster Web Site (SOUDERS, 2009),
consideradas as principais referências na área. Promovida pela O’Reilly Media, a conferência
anual Velocity “Web Performance and Operations” reune o conhecimento no estado da arte
dessa área.
3.1 Técnicas de otimização
Muitas técnicas surgiram com intuito de otimizar o carregamento e execução de
páginas. Esse tópico apresenta as principais técnicas que são baseadas em dois princípios
de desempenho para aplicações distribuídas:
• Diminuir o tamanho dos requisições: diminuir o payload, ou seja, o volume de dados
trafegados.
• Diminuir a quantidade de requisições: minimizar o número de invocações remotas. Na
Web, isso significa diminuir as requisições feitas na página para recursos externos –
arquivos JavaScript, CSS, imagens, vídeos, Flash, etc.
Algumas das principais técnicas são descritas a seguir.
Compressão HTTP
Todo conteúdo textual HTML, CSS, JavaScript, etc, é comprimido antes de ser
enviado para o cliente, podendo chegar a reduções de mais de 50% do tráfego total.
Minificação
Pode ser utilizada para diminuir o número de requisições através da concatenação
de arquivos, remover comentários, espaços em branco, substituir variáveis por tokens
menores, trim de URLs.
Otimizar imagens
Dentro de um arquivo PNG ou JPG muitos dados são armazenados. Além das
informações da imagem em si, há metadados como EXIF, e às vezes, até mesmo uma
miniatura da própria imagem. Nada disso é necessário para renderizar a imagem na tela e
podem ser removidos. Esse é o tipo de otimização conhecida como lossless, a qual não há
perda de qualidade visual. É possível ainda remover o excesso de pixels, comprimir, agrupar
(sprites), dimensionar inserindo no campo <img> o seu tamanho para evitar um reflow,
realizar carregamento sobre demanda, entre outras otimizações possíveis.
Data URIs
Da mesma forma como é possível embutir conteúdos de CSS e JavaScript do
HTML quando conveniente, com data URIs, pode-se embutir imagens e outros elementos
binários. A idéia é transformar os dados binários de uma imagem em base64 e colocar
diretamente no src de uma imagem.
CSS no topo do HTML
Colocar o CSS mais abaixo no código HTML causaria o efeito conhecido como
FOUC (Flash of Unstyled Content), onde página é renderizada sem estilo e, quando o CSS
acaba de carregar, ela é redesenhada com o estilo. Embora isso faça com que a página
comece a ser exibida antes para o usuário, na maioria das aplicações, mostrar uma página
sem estilos não tem valor algum para o usuário. O layout fica sem estrutura, sem
organização, e o efeito é aparentar que a página está demorando mais para carregar.
JavaScript no fim do HTML
Código JavaScript, interno ou externo, bloqueia a renderização de tudo que vem
abaixo dele. Em alguns navegadores, bloqueia inclusive o carregamento de componentes
seguintes. Para evitar esse bloqueio, o JavaScript deve ser carregado o mais abaixo no
documento HTML, se possível, logo antes de fechar o body. O efeito mais comum de
JavaScript mal posicionado é a tela ficar em branco durante muito tempo, adiando o início da
renderização.
Externar grandes CSSs e JavaScript
Em algumas circunstâncias, JavaScript e CSS internos ao HTML que sejam muito
grandes (muito código), é preferível removê-los do HTML. Dessa forma, apesar da
necessidade de uma requisição a mais para se carregar o arquivo, ele externo torna-se
“cacheável” pelo navegador, fazendo com que em solicitações futuras do HTML não haja
necessidade de carregá-lo.
Internalizar CSS e JavaScript
Em conteúdo CSS e JavaScript críticos para a renderização da aplicação, colocá-
los interno ao HTML reduz o tempo de carregamento.
Local storage cache
Para o conteúdo que foi carregado em linha, ou seja, interno ao HTML, existe a
possibilidade de disponibilizá-lo em cache através do local storage, para que em acessos
futuros esse conteúdo já esteja disponível.
Melhorar o parse do HTML
Adicionar <head> caso não esteja presente ou combinar múltiplos <head> em
apenas um, melhora a análise do documento.
DNS prefetch
O tempo de resolução de DNS varia de menos 1 milissegundo para resultados em
cache local à centenas de milissegundos. Assim, prefetch pode contribuir de forma
significativa para a redução do tempo de carregamento total de páginas.
3.2 Ferramentas
Para avaliar o desempenho de carregamento e execução de aplicações Web, faz-
se necessária a utilização de ferramentas de profiling. Entre as mais comuns disponíveis no
mercado está o Pingdom, Load Impact, Google PageSpeed, Gtmetrix, entre outras. Nesse
trabalho será utilizado o JSPerf para comparações de desempenho, WebPageTest para
testar o carregamento e o Google DevTools para demais testes de execução, carregamento
e mensuração. A escolha dessas ferramentas se deu por conta da familiaridade do autor com
elas. Obviamente poder-se-ia utilizar outras, contanto que abrangessem todos os itens
avaliados nos testes. Os navegadores utilizados serão o Google Chrome e o Mozilla Firefox.
3.2.1. JSPerf
É uma ferramenta online que utiliza a engine Benchmark.js e permite a criação de
testes a fim de comparar o desempenho de implementações diferentes. Os resultados dos
testes do navegador utilizado pelo usuário entram para uma estatística compartilhada por
outros usuários que também já executaram o mesmo teste. Dessa maneira funciona como
um meio fácil de criar e compartilhar casos de teste, comparando o desempenho de
diferentes trechos de JavaScript mesmo em navegadores distintos.
3.2.2 Google DevTools
O Chrome Developer Tools ou apenas DevTools, é um conjunto de ferramentas
para criação e depuração de páginas Web inserido no Google Chrome. O DevTools permite
aos desenvolvedores acesso às partes internas do navegador e de sua aplicação. Cada item
da barra de ferramentas e painel correspondente permite que se trabalhe com um tipo
específico de informações da aplicação, incluindo os elementos DOM, recursos e fontes. Em
geral, há oito grupos principais de ferramentas disponíveis no DevTools: Elements, Network,
Figura 11: Aba principal do DevTools.
Sources, Timeline, Profiles, Resources, Audits e Console, como exibe o topo da figura 11.
O painel Timeline (figura 12) oferece uma visão completa sobre onde o tempo é
gasto quando sua página está sendo manipulada ou carregada. Todos os eventos, desde o
carregamento de recursos para análise do JavaScript, cálculo de estilos, e redesenho são
plotados em uma linha do tempo. O painel Profiles permite traçar o perfil de tempo de
execução e uso de memória da aplicação. Inclui um perfil CPU, um perfil JavaScript e um
perfil Heap que auxilia a entender onde os recursos estão sendo consumidos. O perfil CPU
mostra onde o tempo de execução é gasto em funções de JavaScript, enquanto o perfil Heap
mostra a distribuição de memória por objetos JavaScript e nós DOM relacionados. O perfil
JavaScript exibe onde o tempo de execução é gasto nos scripts.
A gravação da figura 12 é de uma página carregada no Chrome. O primeiro
Figura 12: Aba Timeline do DevTools.
registro (Send Request) é o pedido HTTP do navegador para a página, seguido por um
registro Receive Response (para a resposta HTTP correspondente), alguns recebem
registros de dados (para os dados reais de página) e, em seguida, um registro Finish
Loading. A Timeline anota cada gravação com uma linha azul e uma vermelha que indicam,
respectivamente, quando os eventos DOMContentLoaded e onLoad foram disparados pelo
navegador. O evento DOMContentLoaded é acionado quando todo o conteúdo DOM da
página foi carregado e analisado, enquanto o evento onLoad é acionado uma vez que todos
os recursos do documento (imagens e arquivos CSS e assim por diante) foram totalmente
carregados.
3.2.3 WebPageTest
A WebPageTest é uma ferramenta parecida com o Google PageSpeed e o
Pingdom que realiza uma análise do que pode ser melhorado na página para diminuir o seu
tempo de carregamento. É possível através dele, testar de acordo com a localidade e o
navegador de sua preferência. Também é possível simular velocidades reais de usuários.
Oferece testes simples ou avançados incluindo transações com vários passos, capturas de
vídeo e bloqueio de conteúdo. A figura 13 exibe a página inicial já configurada.
Figura 13: Página inicial do WebPageTest
4. Propostas de otimização
Ao longo do capítulo serão propostas formas de otimização para o processamento
de páginas e aplicações Web, não necessariamente caracterizadas como técnicas de
programação, mas muito mais como algoritmos de ferramentas de pré-processamento de
recursos.
4.1 Código específico
Através do cabeçalho user-agent é possível o servidor identificar de qual
navegador procede a requisição. Dessa maneira é possível utilizá-lo como método para
decidir qual conteúdo entregar, de tal forma que o conteúdo entregue seja somente aquele
que será utilizado por aquele navegador específico. Essa abordagem nos garante duas
possibilidades de otimização. A primeira é a de que dessa forma é possível reduzir o
conteúdo total a ser entregue, melhorando então o consumo de banda e o tempo total de
carregamento. A segunda é a de eliminação de testes no código que avaliam em qual
navegador está sendo executado, melhorando, por conseguinte, o seu tempo de execução.
Portanto, nesse modelo o processo de otimizar consiste na eliminação de blocos de código
pertencentes a navegadores distintos, juntamente com os testes correspondentes.
Dentro dessa proposta, um código CSS semelhante à figura 14, onde há
tratamento para os navegadores mais utilizados caso haja implementações distintas, poderia
ser reduzido para um código equivalente à figura 15, quando otimizado para executar em
algum navegador cujo motor de renderização fosse o WebKit, por exemplo. Testes de
plataforma em código JavaScript, como mostra a figura 16, também poderiam ser eliminados.
4.2 JavaScript otimizado
É possível utilizar o código otimizado através da proposta 1 como código de
entrada para a proposta 2. Sendo assim, os recursos estão agora formatados para um
navegador alvo (Chrome, Firefox, Opera, etc), porém não há garantia de que seu conteúdo
(código) esteja otimizado para este mesmo navegador. Em outras palavras, desempenho em
JavaScript é algo muito variável de navegador para navegador e mesmo entre versões do
mesmo navegador, pode haver diferença significativa em algumas operações. Para descobrir
qual implementação é mais rápida para um determinado cenário, é necessário testá-la e
através de uma ferramenta, compará-la em relação ao seu tempo de execução. Para isso é
necessário avaliar algumas operações comuns em JavaScript e classificá-las.
• Repetições9: como mostra a figura 17, para o navegador utilizado, a melhor forma de
9http://jsperf.com/repeti-es/2
Figura 14: Código CSS com propriedade background-image com fallback para demais navegadores.
Figura 15: Código CSS com propriedade background-image com suporte apenas ao WebKit.
Figura 16: JavaScript que avalia em qual navegador o código está operando.
se escrever um laço de repetição no Chrome 38 é utilizando o while reverso, enquanto
no Firefox 31 é através do while tradicional, como mostra a figura 18.
• Testes10: como ilustra a figura 19, a melhor maneira de se escrever um teste no
Chrome é através do if, enquanto no Firefox, como mostra a figura 20, é através da
lookup table.
• Concatenação de strings11: as figuras 21 e 22 exibem resultados dos testes entre
algumas formas de se concatenar strings no Chrome e Firefox respectivamente.
• Arredondamento12: as figuras 23 e 24 mostram resultados dos testes entre algumas
formas de se arredondar números no Chrome e Firefox.
Muitas outras avaliações são possíveis além dessas, como por exemplo o casting de um
número em string, que pode ser realizado através do construtor Number, da função parseInt
ou de operadores binários. É possível avaliar o acesso à variáveis de escopos, funções em
linha, seletor de elementos no DOM, substituição da função innerHTML por createElement e
appendChild, entre uma infinidade de operações que são mais explorados no apêndice A.
10http://jsperf.com/branches
11http://jsperf.com/concatenar-string/2
12http://jsperf.com/floor-de-um-n-mero
Figura 17: Resultado de desempenho entre as formas de se produzir laços de repetição no Chrome.
Figura 18: Resultado de desempenho entre as formas de se produzir laços de repetição no Firefox.
Figura 19: Resultado de desempenho entre as formas de se produzir testes no Chrome.
Figura 20: Resultado de desempenho entre as formas de se produzir testes no Firefox.
Figura 21: Resultados de desempenho entre as formas de se concatenar strings no Chrome.
Figura 22: Resultados de desempenho entre as formas de se concatenar strings no Firefox.
Figura 23: Resultado de desempenho entre as formas de se arredondar números no Chrome.
Figura 24: Resultado de desempenho entre as formas de se arredondar números no Firefox.
4.3 CSS otimizado
Assim como o JavaScript, seletores CSS apresentam diferente desempenho entre
navegadores. O mesmo processo de avaliação de desempenho pode ser utilizado em
seletores a fim de encontrar aquele que melhor desempenha para o navegador alvo e então
substituí-lo. Porém, nesse caso é necessário não apenas modificar o arquivo CSS, mas
também identificar todas as referências em JavaScript e HTML que pode estar apontando
esse seletor.
4.4 HTML otimizado
Media-types permitem o carregamento de CSS específico de acordo com o tipo de
dispositivo do qual provém o acesso. Por exemplo, o media-type handheld caracteriza um
dispositivo de mão, normalmente com tela pequena e banda limitada. Porém esse tipo de
informação está implícito no user-agent que pode ser utilizado para eliminar possíveis
marcações do HTML enviado ao cliente. A figura 25 é um exemplo de marcação media-
query, técnica que permite adicionar uma expressão lógica ao carregamento da media, que
pode ser eliminada do HTML conhecendo-se o user-agent, tornando assim o arquivo HTML
também menor.
4.5 Web Components
Web Components surge como uma proposta para construção de aplicações Web
baseadas em componentes, o que propicia um ganho de produtividade e qualidade no
Figura 25: Declaração HTML que expressa uma condição para carregamento do CSS.
software produzido. Esse aumento da produtividade é decorrente da reutilização de
componentes existentes, enquanto o aumento da qualidade é uma consequência do fato dos
componentes utilizados na construção de uma aplicação já terem sido empregados e
testados em outros contextos. Por se tratar de uma especificação recente, até o momento
desse trabalho poucos estudos sobre desempenho foram empreendidos. Nesse capítulo são
propostas algumas otimizações consideradas mais relevantes e que foram identificadas
como possíveis gargalos no desempenho de Web Components.
4.5.1 HTML Imports
Identificado como o maior gargalo de desempenho em toda API de Web
Components. Com HTML Imports é possível compor uma cadeia de documentos HTML,
onde um documento requisita o próximo, o próximo requisita seu próximo e assim
sucessivamente, podendo construir uma árvore de documentos relacionados ou uma cadeia,
como exemplifica a figura 26.
Para processar HTML Imports utilizando o protocolo HTTP/1.1 precisamos receber
o primeiro o HTML, avaliá-lo, identificar os recursos necessários, solicitá-los, analisar o
próximo HTML e assim sucessivamente até o último (representado como componente L na
figura 27). O problema é que o navegador vai esperar receber o último HTML para começar a
renderizar alguma coisa na tela. A figura 27 demonstra o tempo total de carregamento de
uma aplicação componentizada que representa a hierarquia expressa na figura 26. Ou seja,
o usuário esperou por 11 segundos com a tela em branco até começar a renderização de
algum conteúdo.
Esse problema de encadeamento dos recursos foi identificado no começo da
especificação e foi adotado um novo campo na tag link capaz de dizer para o navegador
carregar o recurso de forma assíncrona, assim como já existia para script, o campo async.
Figura 26: Documentos relacionados através de HTML Imports.
Figura 27: Carregamento de componentes de forma bloqueante.
Porém, com o carregamento assíncrono é possível estar suscetível a um problema
conhecido como data-race, no caso onde um script de algum componente manipule um
elemento que também será manipulado por outro componente. Em um cenário onde os
componentes fazem parte do caminho crítico de renderização, é possível incorrer com o
efeito de FOUC.
Num cenário onde não é possível utilizar a tag async, como por exemplo o caso
dos componentes dependerem um do outro, é possível utilizar duas abordagens para
melhorar o carregamento. A primeira consiste em percorrer todos os HTMLs e todos os
recursos carregados por eles, colocando-os em linha no primeiro HTML. Essa abordagem
traz uma desvantagem que seria a não possibilidade de cache dos recursos, mesmo que
esse problema possa sem contornado com a técnica de cache no local storage. Para isso, é
possível simplesmente colocar em linha no HTML principal as referências aos recursos dos
componentes.
4.5.2 Shadow DOM
Através do Shadow DOM é possível encapsular o estilo de nossos componentes
de forma a evitar colisão de nomes. Extremamente útil quando estamos trabalhando com
componentes de terceiros. No entanto, esse encapsulamento faz com que não haja
reaproveitamento de código CSS, pois cada componente terá o seu próprio estilo, por mais
que tenham exatamente o mesmo conteúdo de estilo. A proposta para esse cenário consiste
em procurar por classes com estilo equivalente, ou seja, que aplicam as mesmas
propriedades, e externá-las em uma nova classe que seja acessada pelos dois ou mais
componentes, removendo a primeira classe ou apenas as propriedades em comum.
5. Resultados
Os resultados obtidos nos testes de desempenho realizados com o intuito de
avaliar as otimizações propostas no capítulo anterior serão apresentados ao longo do
presente capítulo.
5.1 Código específico
Para avaliar a diferença entre uma versão contendo código otimizado para uma
plataforma específica e outra não otimizada, foi desenvolvida uma aplicação de teste
composta de um HTML e 12 componentes que são carregados em sequência. Cada
componente é composto por um arquivo JavaScript e um CSS. O CSS da aplicação não
otimizada carrega propriedades equivalentes para os demais navegadores (no intuito de dar
suporte a eles), da mesma forma como representada pela figura 14, enquanto na versão
otimizada para o WebKit, carrega apenas sua instrução específica, conforme exemplificado
na figura 15. No código JavaScript, alguns blocos de código comumente utilizados em
aplicações Web foram inseridos de maneira a tentar replicar o comportamento de uma
aplicação real. Os blocos de código inseridos executam as seguintes operações:
• Iteração de array de tamanho 120 mil;
• 370 mil concatenações de string;
• 2.650 milhões arredondamentos de número;
• 1.410 milhões de criações de objeto;
• 7.330 milhões de repetições de teste;
• Testes adicionais para avaliar a plataforma.
Esses valores foram escolhidos de maneira a tentar garantir uma mesma fatia de tempo para
execução de cada bloco de instruções de tipo distinto, ou seja, de forma a tentar garantir
aproximadamente 100 milissegundos de execução de iteração de array, 100 milissegundos
de operações de concatenação de strings, e assim por diante.
Figura 28: Carregamento de recursos com suporte cross-browser no Chrome.
Os critérios de análise dos resultados são o tempo de carregamento, influenciado
pelo tamanho do arquivo, e tempo de execução do script, influenciado pelo tipo e número de
operações realizadas. Foi observada redução no tempo de carregamento de 1.452
milissegundos (figura 30) para 1.318 (figura 31), cerca de 10%, resultante da diminuição dos
dados carregados, que passou de 69.4KB (figura 28) para 27.8KB (figura 29). Também foi
observada uma redução no tempo total de execução do script: de 6.76 segundos (figura 30)
Figura 29: Carregamento dos recursos com suporte apenas ao Chrome.
para 6.48 (figura 31), como consequência da remoção dos testes de plataforma.
Figura 30: Gráfico dos tempos gastos no carregamento e execução dos arquivos de suporte cross-browser no Chrome.
Testando a aplicação através do WebPageTest com as configurações
especificadas pela figura 13, obteve-se os resultados da figura 31 para a aplicação sem
otimização. Os resultados da figura 32 para versão formatada para Google Chrome, onde
observa-se um ganho considerável no tempo de carregamento (Load Time), que passou de
18.943 para 12.929 segundos no primeiro acesso. E 10.809 para 8.628 segundos para os
acessos subsequentes.
Figura 32: Carregamento de recursos com suporte cross-browser no Chrome.
Figura 31: Gráfico dos tempos gastos no carregamento e execução dos arquivos de suporte aoChrome.
5.2 JavaScript otimizado
Com os resultados dos testes das operações em mãos (realizados na sessão 4.2)
é possível substituir as operações de baixo desempenho por equivalentes de desempenho
superior, na mesma aplicação. O tempo de carregamento em relação ao resultado anterior
foi de 6.58 segundos (figura 31) para 2.68 segundos (figura 34), como consequência da
redução do tempo de execução dos scripts que passou de 6.48 (figura 31) para 2.56
segundos (figura 35), uma melhora de cerca de 60%.
Figura 33: Carregamento dos recursos com suporte apenas ao Chrome.
Figura 34: Carregamento dos recursos com suporte ao Chrome e JavaScript otimizado.
Testando a aplicação através do WebPageTest com as configurações
especificadas pela figura 13, obteve-se os resultados da figura 36 para a aplicação otimizada
para o Google Chrome. Reduzindo o tempo de carregamento para 8.005 segundos no
primeiro acesso e para 1.616 segundos nos acessos seguintes.
Figura 36: Carregamento dos recursos com suporte ao Chrome e JavaScript otimizado.
Figura 35: Gráfico dos tempos gastos no carregamento e execução dos arquivos com suporte aoChrome e JavaScript otimizado.
A figura 37 expressa a relação entre as versões de teste apresentadas. Embora
em algumas repetições, como na terceira e nona, o tempo de carregamento da versão
normal tenha sido melhor que a do Chrome, isso é consequência da variação do retardo de
rede, mas no contexto geral é observado o ganho de desempenho.
5.3 HTML Imports
Através da estratégia proposta na sessão 4.4, foi possível reduzir o tempo de
carregamento dos recursos de 11.63 segundos (figura 39) para 6.64 segundos (figura 51).
Priorizando o cache, portanto colocando em linha apenas os recursos dos componentes, foi
possível reduzir para 7.63 segundos, como mostra a figura 52.
Figura 37: Relação entre a versão normal, formatada para o Chrome e a otimizada para oChrome.
1 2 3 4 5 6 7 8 90
5000
10000
15000
20000
25000
Normal Chrome Chrome otimizado
Repetição
Tem
po
Testando a aplicação através do WebPageTest com as configurações
Figura 38: Componentes em linha no primeiro HTML.
Figura 39: Recursos dos componentes em linha no primeiro HTML.
especificadas pela figura 13, obteve-se os resultados da figura 40 para a aplicação carregada
de forma bloqueante. A figura 41 mostra os resultados para o código dos componentes em
linha, e os dados da figura 42 foram obtidos com o recurso em linha no HTML principal.
A figura 43 expressa a relação entre as versões de teste apresentadas, onde
mesmo considerando os retardos de rede, verifica-se o ganho de desempenho nas versões
otimizadas.
Figura 42: Recursos dos componentes em linha no primeiro HTML.
Figura 41: Componentes em linha no primeiro HTML.
Figura 40: Carregamento de componentes de forma bloqueante.
5.4 Shadow DOM
Considerando nossa aplicação de 12 componentes, cada qual com seu estilo
como o da figura 44, que consiste basicamente em uma div com uma letra dentro, de
tamanho relativo ao seu parent e sua cor. O tempo de carregamento é explicitado pela figura
46. Modificando apenas um seletor, (figura 44) em comum com os demais componentes,
reduzimos de 33.1KB (figura 46) para 31.1KB (figura 48), uma diferença de mais de 6% do
tamanho dessa aplicação simples. O estilo resultante do componente é representado pela
figura 45 e o do HTML pela figura 47.
Figura 43: Diferença entre HTML Imports e seus recursos ou código em linha.
1 2 3 4 5 6 7 8 90
5000
10000
15000
20000
25000
30000
Normal Código em linha Recursos em linha
Repetição
Tem
po
Figura 45: Estilo do componente pós otimização.
Figura 46: Carregamento de 12 componentes em uma aplicação com Shadow DOM.
Figura 44: Exemplo de estilo para um componente de teste do Shadow DOM.
Figura 47: Estilo do HTML pós otimização.
Figura 48: Carregamento de 12 componentes em uma aplicação com Shadow DOM otimizado.
Testando a aplicação através do WebPageTest com as configurações
especificadas pela figura 13, obteve-se os resultados da figura 49 para a aplicação com
Shadow DOM normal e os resultados da figura 50 para a aplicação com Shadow DOM
otimizado. Reduzindo o tempo de carregamento (Load Time) de 18.750 segundos para
16.325 no primeiro acesso.
Otimizado
A figura 51 expressa a relação entre as versões de teste apresentadas, embora
nesse teste esteja mais difícil observar o ganho de desempenho, uma vez que as oscilações
são consequências do retardo de rede, observa-se nas imagens anteriores a aplicação do
princípio de otimização de aplicação distribuída referente à redução da quantidade de dados
trafegados. Assim, o ganho no desempenho é relativo à aplicação – o quanto ela se utiliza de
estilos equivalentes será a proporção do quanto otimizado será através dessa proposta.
Figura 49: Aplicação com Shadow DOM.
Figura 50: Aplicação com Shadow DOM otimizado.
Figura 51: Diferença entre a aplicação com Shadow DOM otimizado e não otimizado.
1 2 3 4 5 6 7 8 90
5000
10000
15000
20000
25000
30000
Normal Otimizado
Repetição
Tem
po
6. Conclusão
A forma como um navegador interpreta um determinado trecho de código difere, e
as vezes muito, em relação ao tempo de execução em outro navegador, para o mesmo
trecho. Diferentes implementações têm diferentes resultados para produzir o mesmo efeito.
Através desse trabalho foi possível identificar alguns trechos onde pode haver divergência de
resultado, bem como foi possível avaliar o ganho de desempenho quando expressões são
alteradas para sua versão mais rápida. Antes disso, apenas com a eliminação do código
cross-browser já foi possível observar os ganhos de desempenho e carregamento.
Em Web Components foi identificado como gargalo a questão do não reuso do
estilo encapsulado através de Shadow DOM e também a espera no carregamento em
decorrência do encadeamento de recursos através do HTML Imports. Para o Shadow DOM
foi proposto o pré-processamento dos recursos a fim de identificar blocos de estilo
equivalentes e agrupá-los através de um único seletor, eliminando as redundâncias, o que
resultou em uma aplicação menor (em termos de código), reduzindo por conseguinte o seu
tempo de carregamento. Já no caso dos HTML Imports, mostrou-se benéfica a estratégia
proposta de colocar os recursos em linha, reduzindo o tempo de carregamento da aplicação
de forma considerável.
6.1 Trabalhos futuros
Uma das discussões presentes no ambiente de desenvolvimento Web, até o
momento desse trabalho, é se devemos trabalhar em uma versão específica para algumas
plataformas, como no caso das plataformas mobile, por exemplo, ou se devemos compor
uma versão que se adapta ao dispositivo onde a página foi carregada. Na primeira situação,
o usuário é beneficiado, uma vez que receberá um conteúdo mais leve, específico para o tipo
de dispositivo, enquanto na segunda o desenvolvedor é beneficiado, afinal haverá apenas
uma versão para manutenção. A proposta desse trabalho foi, de certa forma, uma tentativa
de unir os benefícios das duas estratégias, entendendo que precisamos beneficiar tanto o
usuário quanto o desenvolvedor. Ao propor que se utilize o cabeçalho user-agent para decidir
qual versão entregar, este trabalho na verdade sugere:
• O desenvolvimento de uma ferramenta de benchmark13, que avalie o desempenho
entre diferentes navegadores e diferentes versões dos navegadores;
• O desenvolvimento de um pré-processador de recursos, que a partir do código
responsivo gere uma versão específica; ainda se valendo do pré-processador, através
dos resultados do benchmark pode-se substituir instruções pela sua versão de melhor
desempenho;
• Uma modificação na forma como o servidor HTTP negocia o conteúdo, fazendo-o
redirecionar para um conteúdo específico de cada user-agent.
Então, além do pré-processamento de uma versão específica para plataformas
mobile, por exemplo, é possível ainda gerar versões específicas para cada navegador,
otimizando o conteúdo para aquele navegador.
13 Ato de executar um programa de computador, um conjunto de programas ou outras operações, a fim de avaliar o desempenho relativo de um objeto.
Bibliografia
AMAZON. Make Data Useful. Stanford Data Mining. [S.l.]: [s.n.]. 2006.
BERNERS-LEE, Tim. Information Management: A Proposal - W3C. Março, 1989.
BERNERS-LEE, Tim. CAILLIAU, Robert. Application Program Interface Foldoc.Novembro, 1990.
BERNERS-LEE, Tim; FIELDING, R; FRYSTYK, H. Hypertext Transfer Protocol – HTTP/1.0Internet Engineering Task Force. Maio, 1996.
BROWN, A.W.; K.C Wallnau. Component-Based Software Engineering. IEEE ComputerSociety Press, 1996.; Pags. 7-15.
CROCKFORD, D. JSMin, The JavaScript Minifier. Wrrrld Wide Web, 2003. Disponivel em:<http://www.crockford.com/javascript/jsmin.html>. Acesso em: 1 de abril de 2015.
DEREMER, F.. Programming-in-the-large versus programming-in-the-small. IEEETransactions on Software Engineering, 1976.
DIERKS, T.; ALLEN, C. The TLS Protocol Version 1.0 - RFC 2246. Janeiro, 1999.
FLANAGAN, David; FERGUSON, Paula. JavaScript: The Definitive Guide. O'Reilly &Associates, 2002.
FORREST RESEARCH. eCommerce Web Site Performance Today. 2009.
FRAIN, Ben. CSS performance revisited: selectors, bloat and expensive styles.Disponível em: <http://benfrain.com/css-performance-revisited-selectors-bloat-expensive-styles/>. Acesso em: 1 de março de 2015.
KRUCHTEN, P. 2003. The Rational Unified Process: An Introduction. Addison-WesleyLongman Publishing Co., Inc. Boston, MA, USA - 3º edição.
LINDEN, G. Make Data Useful. 2008. Disponível em:<http://www.scribd.com/doc/4970486/Make-Data-Useful-by-Greg-Linden-Amazoncom>.Acesso em: 13 de março de 2015.
LINDEN, G. Marissa Meyer at Web 2.0. 2007. Disponível em:<http://glinden.blogspot.com.br/2006/11/marissa-mayer-at-web-20.html>. Acesso em: 14 demarço de 2015.
MCILROY, M. D. Mass Produced Software Components, NATO Software EngineeringConference Report, Garmisch, Germany, Outubro, 1968, pp. 79-85.
MEENAN, P. About WebPagetest.org. WebPagetest.org, 2008. Disponivel em:<http://www.webpagetest.org/about>. Acesso em: 13 de maio de 2015.
MOZZILA, B. C. Firefox & Page Load Speed - Part II. Blog of Metrics, 2010. Disponivel em:<http://blog.mozilla.org/metrics/2010/04/05/firefox-page-load-speed-%E2%80%93-part-ii/>.Acesso em: 14 de abril de 2015.
NIELSEN, J. Website Response Times. Userit.com, 2010. Disponivel em:<http://www.useit.com/alertbox/response-times.html>. Acesso em: 21 de abril de 2015.
PILGRIM, Mark Pilgrim. DIVE INTO HTML5. Agosto, 2010.
RAGGETT, Dave; WESLEY, Addison. A history of HTML. 1998.
RFC1951. DEFLATE Compressed Data Format Specification version 1.3. IETF. [S.l.].1996.
RFC1952. GZIP file format specification version 4.3. IETF. [S.l.]. 1996.
RFC2318. The text/css Media Type. Internet Engineering Task Force. [S.l.]. 1998.
RFC2397. The "data" URL scheme. IETF. [S.l.]. 1998.
RFC2557. MIME Encapsulation of Aggregate Documents, such as HTML (MHTML). IETF.[S.l.]. 1999.
RFC2616. Hypertext Transfer Protocol -- HTTP/1.1. IETF. [S.l.]. 1999.
RFC6265. HTTP State Management Mechanism. Internet Engineering Task Force. [S.l.].2011.
RFC793. Transmission Control Protocol. Internet Engineering Task Force. [S.l.]. 1981.
SOUDERS, S. High Performance Web Sites. O'Reilly Media. Setembro, 2007.
SOUDERS, S. Even Faster Web Sites. O'Reilly Media. Junho, 2009.
STEFANOV, S. Psychology of Performance. Velocity. [S.l.]: [s.n.]. 2010.
SZYPERSKI, C.. Sumary of the Second International Workshop on Component OrientedProgramming. 2º WCOP Finland, 1997.
W3C. Introduction to Web Components. Disponível em:<http://www.w3.org/TR/components-intro/>. Acesso em: 1 de abril de 2015.
Apêndice A
O intuito desse apêndice é apresentar outros resultados de avaliações de
desempenho de recursos de uma página HTML.
JavaScript
A figura 52 exibe resultados de desempenho entre as formas de se
aplicar/modificar propriedades CSS via JavaScript sobre elementos HTML, no navegador
Chrome, enquanto a figura 53 apresenta os resultados do mesmo teste para o navegador
Firefox. A figura 54 faz um comparativo entre os navegadores já testados.
Figura 52: Resultado de desempenho entre as formas de se aplicar/modificar propriedades CSS noChrome.
Figura 53: Resultado de desempenho entre as formas de se aplicar/modificar propriedades CSS noChrome.
A figura 55 exibe resultados de desempenho entre as formas de se exibir e
esconder um elemento HTML no navegador Chrome, enquanto a figura 68 apresenta os
resultados do mesmo teste para o navegador Firefox.
Figura 54: Resultado de desempenho entre as formas de se aplicar/modificarpropriedades CSS entre versões do Chrome e Firefox.
Figura 55: Resultado de desempenho entre as formas de se exibir e esconder um elemento HTMLno Chrome.
Figura 56: Resultado de desempenho entre as formas de se aplicar/modificar propriedades CSS noFirefox.
CSS
Ben Frain em seu artigo intitulado CSS performance revisited: selectors, bloat and
expensive styles (FRAIN, 2014) propõe alguns testes de seletores CSS e apresenta os
resultados, para os casos abaixo, na figura 57.
1. Data attribute;
2. Data attribute (qualified);
3. Data attribute (unqualified but with value);
4. Data attribute (qualified with value);
5. Multiple data attributes (qualified with values);
6. Solo pseudo selector (e.g. :after);
7. Combined classes (e.g. class1.class2);
8. Multiple classes;
9. Multiple classes with child selector;
10. Partial attribute matching (e.g. [class^=“wrap”]);
11. nth-child selector;
12. nth-child selector followed by another nth-child selector;
13. Insanity selection (all selections qualified, every class used e.g. div.wrapper >;
div.tagDiv > div.tagDiv.layer2 > ul.tagUL > li.tagLi > b.tagB > a.TagA.link);
14. Slight insanity selection (e.g. .tagLi .tagB a.TagA.link);
15. Universal selector;
16. Element single;
17. Element double;
18. Element treble;
19. Element treble with pseudo;
20. Single class.
Figura 57: Resultados dos testes de desempenho de seletores CSS.
Fonte: http://benfrain.com/css-performance-revisited-selectors-bloat-expensive-styles/
Anexo I – Artigo
Otimização de Desempenho em Aplicações Web e WebComponents
Diego Lagranha Weiss
Departamento de Informática e Estatística – Universidade Federal de Santa Catarina(UFSC)
Caixa Postal 476 – 88.040970 – Florianópolis – SC – [email protected]
Abstract. Originally designed to assist information sharing betweenlaboratories, Web pages got bigger and became complete applications on theclient side, even have become a great mechanism for conducting business.Efforts to optimization result immediately in financial impacts. The purposeof this article is to present new optimization possibilities, considering alsonew features that have not been explored in relation to its performance,trying to understand the bottlenecks and how to circumvent them.
Resumo. Originalmente pensadas para auxiliar o compartilhamento deinformações entre laboratórios, as páginas Web cresceram se tornaramaplicações completas no lado do cliente, inclusive se tornaram um grandemecanismo para realização de negócios. Esforços para otimização resultamde forma imediata em impactos financeiros. O intuito desse artigo consisteem apresentar novas possibilidades de otimização, considerando tambémnovos recursos que ainda não foram explorados em relação ao seudesempenho, tentando entender os gargalos e como contornálos.
1. Introdução
A World Wide Web, ou apenas Web, foi concebida em 1989 como um sistema deinformação para melhor gerenciar as informações produzidas no laboratórioCERN (Organização Européia para a Pesquisa Nuclear) (BERNERSLEE, 1989).Desenvolvimentos mais recentes desta tecnologia têm permitido distribuir, juntoàs informações, objetos e programas que realizam atividades no clienteconsumidor da informação. Também tem permitido o desenvolvimento deaplicações orientadas a componentes junto ao cliente. Nesse contexto identifico ospossíveis gargalos, apresento as técnicas existentes e proponho modificações comintuito de otimizar o seu tempo de carregamento e de execução.
2. Problema
A forma de desenvolver na Web mudou bastante nos últimos 25 anos. No começofaziase praticamente tudo no lado do servidor e o problema de reuso decomponentes de software estava praticamente resolvido com adoção detecnologias como Rails ou templates de Django. Por conta do aumento do poderde processamento do cliente o cenário mudou. De motores JavaScript de melhordesempenho, passouse a um maior número de aplicações mistas, onde delegasemuita lógica para o cliente.
À medida que os navegadores evoluem, as especificações tambémmelhoram, por isso diferentes versões do mesmo navegador podem apresentarpáginas HTML de maneira diferente entre si. Web Components (W3C, 2014) é umconjunto de especificações (Custom Elements, Shadow DOM, Templates, HTMLImports), influenciadas por frameworks e bibliotecas JavaScript, que auxiliam odesenvolvedor a escrever páginas HTML baseadas em componentes,padronizando as suas principais funcionalidades. Desse modo, Web Componentsauxiliam o desempenho, implementando no navegador recursos que só estariamdisponíveis através de carregamentos externos. No entanto, foi necessárioidentificar gargalos dessas especificações com o intuito de propor técnicas quecoibem a perda de desempenho. O impacto no desempenho pode ser aferido dediversas maneiras em aplicações Web.
Os desenvolvedores da Web têm que lidar com todas essas questões,pois os programas com os quais o público visualizará o conteúdo podem ser muitodiferentes. Além do mais, o desempenho do conteúdo entregue ao cliente se tornoumais crítico, uma vez que passou a representar o maior tempo da aplicação(SOUDERS, 2007). Aplicações crossbrowser (aquelas capazes de suportarmúltiplos navegadores), que representam uma solução para lidar com as diferentesimplementações de navegadores, em geral requerem a entrega de mais conteúdoao cliente, aumentando, por conseguinte, o tempo de carregamento da aplicação.
3. Objetivo
O objetivo deste artigo consiste em apresentar e avaliar propostas que otimizem otempo de carregamento de aplicações Web, sejam elas aplicações simples, crossbrowser e/ou consumidoras de Web Components. Propostas não necessariamentecaracterizadas como técnicas de programação, mas muito mais como algoritmos aserem implementados em ferramentas de préprocessamento de recursos. Paraisso, fazse necessário primeiro detalhar a estrutura de uma aplicação Web eidentificar os seus possíveis gargalos de desempenho.
4. Desempenho
O desempenho tornouse um importante fator para o sucesso de aplicações Web.Não somento no aspecto comercial, como também no impacto no contexto social,
como a educação, entretenimento e muitas outras áreas que se utilizam dasfacilidades da Web para alcançar seu público.
Como um sistema distribuído, podese aferir o tempo de carregamentode recursos e a ordem como são carregados, sendo que esse tempo está em funçãoda taxa de transmissão do cliente e o tamanho do recurso solicitado. O bloqueio deconteúdo gráfico em páginas Web pode trazer uma sensação de lentidão maior,prejudicando a experiência do usuário. Executar código JavaScript pode tambémproduzir diferentes resultados de desempenho em navegadores distintos. O mesmoocorre com a renderização dos elementos HTML. Isso acontece por conta dadiferença entre implementações dos navegadores e de seus motores gráficos e deJavaScript.
5. Propostas
Ao longo dessa sessão serão propostas formas de otimização para o processamentode páginas e aplicações Web, não necessariamente caracterizadas como técnicasde programação, mas muito mais como algoritmos de ferramentas de préprocessamento de recursos.
5.1. Código específico
Através do cabeçalho useragent é possível o servidor identificar de qualnavegador procede a requisição. Dessa maneira é possível utilizálo como métodopara decidir qual conteúdo entregar, de tal forma que o conteúdo entregue sejasomente aquele que será utilizado por aquele navegador específico. Essaabordagem nos garante duas possibilidades de otimização. A primeira é a de quedessa forma é possível reduzir o conteúdo total a ser entregue, melhorando então oconsumo de banda e o tempo total de carregamento. A segunda é a de eliminaçãode testes no código que avaliam em qual navegador está sendo executado,melhorando, por conseguinte, o seu tempo de execução. Portanto, nesse modelo oprocesso de otimizar consiste na eliminação de blocos de código pertencentes anavegadores distintos, juntamente com os testes correspondentes.
Figura 2: Código CSS com propriedade backgroundimage com suporte apenas aoWebKit.
Figura 1: Código CSS com propriedade backgroundimage com fallback parademais navegadores.
Para avaliar a diferença entre uma versão contendo código otimizadopara uma plataforma específica e outra não otimizada, foi desenvolvida umaaplicação de teste composta de um HTML e 12 componentes que são carregadosem sequência. Cada componente é composto por um arquivo JavaScript e umCSS. O CSS da aplicação não otimizada carrega propriedades equivalentes para osdemais navegadores (no intuito de dar suporte a eles, da mesma forma comorepresentada pela figura 1, enquanto na versão otimizada para o WebKit, carregaapenas sua instrução específica, conforme exemplificado na figura 2. No códigoJavaScript, alguns blocos de código comumente utilizados em aplicações Webforam inseridos de maneira a tentar replicar o comportamento de uma aplicaçãoreal. Os blocos de código inseridos executam as seguintes operações:
• Iteração de array de tamanho 120 mil;
• 370 mil concatenações de string;
• 2.650 milhões arredondamentos de número;
• 1.410 milhões de criações de objeto;
• 7.330 milhões de repetições de teste;
• Testes adicionais para avaliar a plataforma.
Esses valores foram escolhidos de maneira a tentar garantir umamesma fatia de tempo para execução de cada bloco de instruções de tipo distinto,ou seja, de forma a tentar garantir aproximadamente 100 milissegundos deexecução de iteração de array, 100 milissegundos de operações de concatenaçãode strings, e assim por diante.
Os critérios de análise dos resultados são o tempo de carregamento,influenciado pelo tamanho do arquivo, e tempo de execução do script,influenciado pelo tipo e número de operações realizadas. Foi observada reduçãono tempo de carregamento de 1.452 milissegundos para 1.318, cerca de 10%,resultante da diminuição dos dados carregados, que passou de 69.4KB para27.8KB. Também foi observada uma redução no tempo total de execução doscript: de 6.76 segundos para 6.48, como consequência da remoção dos testes deplataforma.
5.2. JavaScript otimizado
É possível utilizar o código otimizado através da proposta 5.1 (código específico)como código de entrada desta proposta. Sendo assim, os recursos estão agoraformatados para um navegador alvo (Chrome, Firefox, Opera, etc), porém não hágarantia de que seu conteúdo (código) esteja otimizado para este mesmonavegador. Em outras palavras, desempenho em JavaScript é algo muito variávelde navegador para navegador e mesmo entre versões do mesmo navegador, podehaver diferença significativa em algumas operações. Para descobrir qualimplementação é mais rápida para um determinado cenário, é necessário testála e
através de uma ferramenta, comparála em relação ao seu tempo de execução. Paraisso é necessário avaliar algumas operações comuns em JavaScript e classificálas.
• Repetições: para o navegador utilizado, a melhor forma de se escrever umlaço de repetição no Chrome 38 é utilizando o while reverso, enquanto noFirefox 31 é através do while tradicional.
• Testes: a melhor maneira de se escrever um teste no Chrome é através doif, enquanto no Firefox, é através da lookup table.
Muitas outras avaliações são possíveis além dessas, como por exemplo ocasting de um número em string, que pode ser realizado através do construtor Number,da função parseInt ou de operadores binários. É possível avaliar o acesso à variáveis deescopos, funções em linha, seletor de elementos no DOM, substituição da funçãoinnerHTML por createElement e appendChild, entre uma infinidade de operações.
Com os resultados dos testes das operações em mãos é possívelsubstituir as operações de baixo desempenho por equivalentes de desempenhosuperior, na mesma aplicação. Assim, o tempo de carregamento em relação aoresultado anterior foi de 6.58 segundos para 2.68 segundos, como consequência daredução do tempo de execução dos scripts que passou de 6.48 para 2.56 segundos,uma melhora de cerca de 60%.
5.3. CSS otimizado
Assim como o JavaScript, seletores CSS apresentam diferente desempenho entrenavegadores. O mesmo processo de avaliação de desempenho pode ser utilizadoem seletores a fim de encontrar aquele que melhor desempenha para o navegadoralvo e então substituílo. Porém, nesse caso é necessário não apenas modificar oarquivo CSS, mas também identificar todas as referências em JavaScript e HTMLque pode estar apontando esse seletor.
5.4. HTML otimizado
Mediatypes permitem o carregamento de CSS específico de acordo com o tipo dedispositivo do qual provém o acesso. Por exemplo, o mediatype handheldcaracteriza um dispositivo de mão, normalmente com tela pequena e bandalimitada. Porém esse tipo de informação está implícito no useragent que pode serutilizado para eliminar possíveis marcações do HTML enviado ao cliente.
5.5. HTML Imports em linha
Identificado como o maior gargalo de desempenho em toda API de WebComponents. Com HTML Imports é possível compor uma cadeia de documentosHTML, onde um documento requisita o próximo, o próximo requisita seu próximoe assim sucessivamente, podendo construir uma árvore de documentosrelacionados ou uma cadeia. Para processar HTML Imports utilizando o protocoloHTTP/1.1 precisamos receber o primeiro o HTML, avaliálo, identificar os
recursos necessários, solicitálos, analisar o próximo HTML e assimsucessivamente até o último. O problema é que o navegador vai esperar receber oúltimo HTML para começar a renderizar alguma coisa na tela.
Esse problema de encadeamento dos recursos foi identificado nocomeço da especificação e foi adotado um novo campo na tag link capaz de dizerpara o navegador carregar o recurso de forma assíncrona, assim como já existiapara script, o campo async. Porém, com o carregamento assíncrono é possívelestar suscetível a um problema conhecido como datarace, no caso onde um scriptde algum componente manipule um elemento que também será manipulado poroutro componente. Em um cenário onde os componentes fazem parte do caminhocrítico de renderização, é possível incorrer com o efeito de FOUC. Num cenárioonde não é possível utilizar a tag async, como por exemplo o caso doscomponentes dependerem um do outro, é possível utilizar duas abordagens paramelhorar o carregamento. A primeira consiste em percorrer todos os HTMLs etodos os recursos carregados por eles, colocandoos em linha no primeiro HTML.Essa abordagem traz uma desvantagem que seria a não possibilidade de cache dosrecursos, mesmo que esse problema possa sem contornado com a técnica de cacheno local storage. Para isso, é possível simplesmente colocar em linha no HTMLprincipal as referências aos recursos dos componentes.
Através da estratégia, conseguimos reduzir o tempo de carregamentodos recursos de 11.63 segundos para 6.64 segundos em uma rede local.Priorizando o cache, portanto colocando em linha apenas os recursos doscomponentes, foi possível reduzir para 7.63 segundos.
5.6. Shadow DOM equivalente
Através do Shadow DOM é possível encapsular o estilo de nossos componentes deforma a evitar colisão de nomes. Extremamente útil quando estamos trabalhandocom componentes de terceiros. No entanto, esse encapsulamento faz com que nãohaja reaproveitamento de código CSS, pois cada componente terá o seu próprioestilo, por mais que tenham exatamente o mesmo conteúdo de estilo. A propostapara esse cenário consiste em procurar por classes com estilo equivalente, ou seja,que aplicam as mesmas propriedades, e externálas em uma nova classe que sejaacessada pelos dois ou mais componentes, removendo a primeira classe ou apenasas propriedades em comum.
Considerando a aplicação de 12 componentes anterior, cada qual comseu estilo, que consiste basicamente em uma div com uma letra dentro, de tamanhorelativo ao seu parent e sua cor. Modificando apenas um seletor, em comum comos demais componentes, reduziuse de 33.1KB para 31.1KB, uma diferença demais de 6% do tamanho dessa aplicação simples.
6. Conclusão
A forma como um navegador interpreta um determinado trecho de código difere, e
as vezes muito, em relação ao tempo de execução em outro navegador, para omesmo trecho. Diferentes implementações têm diferentes resultados para produziro mesmo efeito. Através desse trabalho foi possível identificar alguns trechos ondepode haver divergência de resultado, bem como foi possível avaliar o ganho dedesempenho quando expressões são alteradas para sua versão mais rápida. Antesdisso, apenas com a eliminação do código crossbrowser já foi possível observaros ganhos de desempenho e carregamento.
Em Web Components foi identificado como gargalo a questão do nãoreuso do estilo encapsulado através de Shadow DOM e também a espera nocarregamento em decorrência do encadeamento de recursos através do HTMLImports. Para o Shadow DOM foi proposto o préprocessamento dos recursos afim de identificar blocos de estilo equivalentes e agrupálos através de um únicoseletor, eliminando as redundâncias, o que resultou em uma aplicação menor (emtermos de código), reduzindo por conseguinte o seu tempo de carregamento. Já nocaso dos HTML Imports, mostrouse benéfica a estratégia proposta de colocar osrecursos em linha, reduzindo o tempo de carregamento da aplicação de formaconsiderável.
Uma das discussões presentes no ambiente de desenvolvimento Web,até o momento desse trabalho, é se devemos trabalhar em uma versão específicapara algumas plataformas, como no caso das plataformas mobile, por exemplo, ouse devemos compor uma versão que se adapta ao dispositivo onde a página foicarregada. Na primeira situação, o usuário é beneficiado, uma vez que receberáum conteúdo mais leve, específico para o tipo de dispositivo, enquanto na segundao desenvolvedor é beneficiado, afinal haverá apenas uma versão para manutenção.A proposta desse trabalho foi, de certa forma, uma tentativa de unir os benefíciosdas duas estratégias, entendendo que precisamos beneficiar tanto o usuário quantoo desenvolvedor. Ao propor que se utilize o cabeçalho useragent para decidirqual versão entregar, este trabalho na verdade sugere:
• O desenvolvimento de uma ferramenta de benchmark, que avalie odesempenho entre diferentes navegadores e diferentes versões dosnavegadores;
• O desenvolvimento de um préprocessador de recursos, que a partir docódigo responsivo gere uma versão específica; ainda se valendo do préprocessador, através dos resultados do benchmark podese substituirinstruções pela sua versão de melhor desempenho;
• Uma modificação na forma como o servidor HTTP negocia o conteúdo,fazendoo redirecionar para um conteúdo específico de cada useragent.
Então, além do préprocessamento de uma versão específica paraplataformas mobile, por exemplo, é possível ainda gerar versões específicas paracada navegador, otimizando o conteúdo para aquele navegador.
6. Referências
AMAZON. Make Data Useful. Stanford Data Mining. [S.l.]: [s.n.]. 2006.
BERNERSLEE, Tim. Information Management: A Proposal W3C. Março, 1989.
BERNERSLEE, Tim. CAILLIAU, Robert. Application Program Interface Foldoc.Novembro, 1990.
BERNERSLEE, Tim; FIELDING, R; FRYSTYK, H. Hypertext Transfer Protocol –HTTP/1.0 Internet Engineering Task Force. Maio, 1996.
BROWN, A.W.; K.C Wallnau. ComponentBased Software Engineering. IEEEComputer Society Press, 1996.; Pags. 715.
CROCKFORD, D. JSMin, The JavaScript Minifier. Wrrrld Wide Web, 2003.Disponivel em: <http://www.crockford.com/javascript/jsmin.html>. Acesso em: 1 deabril de 2015.
DEREMER, F.. Programminginthelarge versus programminginthesmall.IEEE Transactions on Software Engineering, 1976.
DIERKS, T.; ALLEN, C. The TLS Protocol Version 1.0 RFC 2246. Janeiro, 1999.
FLANAGAN, David; FERGUSON, Paula. JavaScript: The Definitive Guide.O'Reilly & Associates, 2002.
FORREST RESEARCH. eCommerce Web Site Performance Today. 2009.
FRAIN, Ben. CSS performance revisited: selectors, bloat and expensive styles.Disponível em: <http://benfrain.com/cssperformancerevisitedselectorsbloatexpensivestyles/>. Acesso em: 1 de março de 2015.
KRUCHTEN, P. 2003. The Rational Unified Process: An Introduction. AddisonWesley Longman Publishing Co., Inc. Boston, MA, USA 3º edição.
LINDEN, G. Make Data Useful. 2008. Disponível em:<http://www.scribd.com/doc/4970486/MakeDataUsefulbyGregLindenAmazoncom>. Acesso em: 13 de março de 2015.
LINDEN, G. Marissa Meyer at Web 2.0. 2007. Disponível em:<http://glinden.blogspot.com.br/2006/11/marissamayeratweb20.html>. Acesso em:14 de março de 2015.
MCILROY, M. D. Mass Produced Software Components, NATO SoftwareEngineering Conference Report, Garmisch, Germany, Outubro, 1968, pp. 7985.
MEENAN, P. About WebPagetest.org. WebPagetest.org, 2008. Disponivel em:<http://www.webpagetest.org/about>. Acesso em: 13 de maio de 2015.
MOZZILA, B. C. Firefox & Page Load Speed Part II. Blog of Metrics, 2010.Disponivel em: <http://blog.mozilla.org/metrics/2010/04/05/firefoxpageloadspeed%E2%80%93partii/>. Acesso em: 14 de abril de 2015.
NIELSEN, J. Website Response Times. Userit.com, 2010. Disponivel em:<http://www.useit.com/alertbox/responsetimes.html>. Acesso em: 21 de abril de 2015.
PILGRIM, Mark Pilgrim. DIVE INTO HTML5. Agosto, 2010.
RAGGETT, Dave; WESLEY, Addison. A history of HTML. 1998.
RFC1951. DEFLATE Compressed Data Format Specification version 1.3. IETF.[S.l.]. 1996.
RFC1952. GZIP file format specification version 4.3. IETF. [S.l.]. 1996.
RFC2318. The text/css Media Type. Internet Engineering Task Force. [S.l.]. 1998.
RFC2397. The "data" URL scheme. IETF. [S.l.]. 1998.
RFC2557. MIME Encapsulation of Aggregate Documents, such as HTML(MHTML). IETF. [S.l.]. 1999.
RFC2616. Hypertext Transfer Protocol HTTP/1.1. IETF. [S.l.]. 1999.
RFC6265. HTTP State Management Mechanism. Internet Engineering Task Force.[S.l.]. 2011.
RFC793. Transmission Control Protocol. Internet Engineering Task Force. [S.l.].1981.
SOUDERS, S. High Performance Web Sites. O'Reilly Media. Setembro, 2007.
SOUDERS, S. Even Faster Web Sites. O'Reilly Media. Junho, 2009.
STEFANOV, S. Psychology of Performance. Velocity. [S.l.]: [s.n.]. 2010.
SZYPERSKI, C.. Sumary of the Second International Workshop on ComponentOriented Programming. 2º WCOP Finland, 1997.
W3C. Introduction to Web Components. Disponível em:<http://www.w3.org/TR/componentsintro/>. Acesso em: 1 de abril de 2015.
Anexo II – Código
Script.js sem otimizações
console.time('time');
var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
// Opera 8.0+ (UA detection to detect Blink/v8powered Opera)
var isFirefox = typeof InstallTrigger !== 'undefined'; // Firefox 1.0+
var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
// At least Safari 3+: '[object HTMLElementConstructor]'
var isChrome = !!window.chrome && !isOpera; // Chrome 1+
var isIE = /*@cc_on!@*/false || !!document.documentMode; // At least IE6
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
if (isOpera) {
for (var i = 0; i < arr.length; ++i) {
arr[i];
}
} else if (isFirefox) {
var i = 0;
while (i < arr.length) {
arr[i];
i++;
}
} else if (isSafari) {
for (var i = arr.length; i;) {
arr[i];
}
} else if (isChrome) {
arr.forEach(function (x) {
x;
});
} else {
var i;
for (i = 0; i < arr.length; i += 1) {
arr[i];
}
}
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
if (isOpera) {
str = '';
for (j = 0; j < timesAppend; j++) {
str += 'Quick ' + w1 + ' fox ' + w2 + ' over the ' + w3 + ' dog. ';
}
} else if (isFirefox) {
str = '';
for (j = 0; j < timesAppend; j++) {
str += 'Quick ';
str += w1;
str += ' fox ';
str += w2;
str += ' over the ';
str += w3;
str += ' dog. ';
}
} else if (isSafari) {
str = '';
for (j = 0; j < timesAppend; j++) {
str.concat('Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. ');
}
} else if (isChrome) {
arr = [];
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
} else {
str = '';
for (j = 0; j < timesAppend; j++) {
str.concat('Quick ');
str.concat(w1);
str.concat(' fox ');
str.concat(w2);
str.concat(' over the ');
str.concat(w3);
str.concat(' dog. ');
}
}
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
if (isOpera) {
num = num & 0xFFFFFFFF;
} else if (isFirefox) {
num = ~~num;
} else if (isSafari) {
num = num << 0;
} else if (isChrome) {
num = Math.floor(num);
} else {
num = num ^ 0 ^ 0;
}
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
if (isOpera) {
var object = new Klass();
} else {
var object = Object.create(Klass.prototype);
}
}
// Testes
function ifElseTest(stuff) {
if (stuff === 'pizza') {
return 'food';
} else if (stuff === 'house') {
return 'building';
} else if (stuff === 'table') {
return 'furniture';
} else if (stuff === 'car') {
return 'driving';
} else if (stuff === 'water') {
return 'drink';
} else if (stuff === 'air') {
return 'nothing';
}
}
function switchTest(stuff) {
switch (stuff) {
case 'pizza':
return 'food';
break;
case 'house':
return 'building';
break;
case 'table':
return 'furniture';
break;
case 'car':
return 'driving';
break;
case 'water':
return 'drink';
break;
case 'air':
return 'nothing';
break;
}
}
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
if (isOpera) {
ifElseTest('pizza');
ifElseTest('water');
ifElseTest('air');
} else if (isFirefox || isSafari) {
switchTest('pizza');
switchTest('water');
switchTest('air');
} else {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
}
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = './componentA/style.css';
document.head.appendChild(link);
console.timeEnd('time');
Style.css sem otimizações
#componentA {
backgroundimage: webkitlineargradient(top right, #FF0000, #FF0000);
backgroundimage: mozlineargradient(top right, #FF0000, #FF0000);
backgroundimage: mslineargradient(top right, #FF0000, #FF0000);
backgroundimage: olineargradient(top right, #FF0000, #FF0000);
backgroundimage: lineargradient(top right, #FF0000, #FF0000);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
Index.html
<!DOCTYPE html>
<html>
<head>
<style>
#layout {
width: 1024px;
height: 600px;
}
#layout > div {
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
</head>
<body>
<div id='layout'>
<div id='componentA'>A</div>
<div id='componentB'>B</div>
<div id='componentC'>C</div>
<div id='componentD'>D</div>
<div id='componentE'>E</div>
<div id='componentF'>F</div>
<div id='componentG'>G</div>
<div id='componentH'>H</div>
<div id='componentI'>I</div>
<div id='componentJ'>J</div>
<div id='componentK'>K</div>
<div id='componentL'>L</div>
</div>
<script src='./componentA/script.js'></script>
<script src='./componentB/script.js'></script>
<script src='./componentC/script.js'></script>
<script src='./componentD/script.js'></script>
<script src='./componentE/script.js'></script>
<script src='./componentF/script.js'></script>
<script src='./componentG/script.js'></script>
<script src='./componentH/script.js'></script>
<script src='./componentI/script.js'></script>
<script src='./componentJ/script.js'></script>
<script src='./componentK/script.js'></script>
<script src='./componentL/script.js'></script>
</body>
</html>
Script.js específico para o Chrome
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = './componentA/style.css';
document.head.appendChild(link);
console.timeEnd('time');
Script.js otimizado para o Chrome
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
for (var i = 0, max = arr.length; i < max; ++i) {
arr[i];
}
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
str = '';
for (j = 0; j < timesAppend; j++) {
str += 'Quick ' + w1 + ' fox ' + w2 + ' over the ' + w3 + ' dog. ';
}
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = num | 0;
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = new Klass();
}
// Testes
function ifElseTest(stuff) {
if (stuff === 'pizza') {
return 'food';
} else if (stuff === 'house') {
return 'building';
} else if (stuff === 'table') {
return 'furniture';
} else if (stuff === 'car') {
return 'driving';
} else if (stuff === 'water') {
return 'drink';
} else if (stuff === 'air') {
return 'nothing';
}
}
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
ifElseTest('pizza');
ifElseTest('water');
ifElseTest('air');
}
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = './componentA/style.css';
document.head.appendChild(link);
console.timeEnd('time');
Style.css específico para o Chrome
#componentA {
backgroundimage: webkitlineargradient(top right, #FF0000, #FF0000);
}
Index.html do HTML Imports não otimizado
<!DOCTYPE html>
<html>
<head>
<style>
#layout {
width: 1024px;
height: 600px;
}
#layout > div {
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
</head>
<body>
<div id='layout'>
<div id='componentA'>A</div>
<div id='componentB'>B</div>
<div id='componentC'>C</div>
<div id='componentD'>D</div>
<div id='componentE'>E</div>
<div id='componentF'>F</div>
<div id='componentG'>G</div>
<div id='componentH'>H</div>
<div id='componentI'>I</div>
<div id='componentJ'>J</div>
<div id='componentK'>K</div>
<div id='componentL'>L</div>
</div>
<link rel='import' href='componentA/index.html'></link>
</body>
</html>
Index.html do componente
<script src='script.js'></script>
<link rel='stylesheet' href='style.css'></link>
<link rel='import' href='../componentB/index.html'></link>
Index.html do HTML Imports com recursos em linha
<!DOCTYPE html>
<html>
<head>
<style>
#layout {
width: 1024px;
height: 600px;
}
#layout > div {
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
</head>
<body>
<div id='layout'>
<div id='componentA'>A</div>
<div id='componentB'>B</div>
<div id='componentC'>C</div>
<div id='componentD'>D</div>
<div id='componentE'>E</div>
<div id='componentF'>F</div>
<div id='componentG'>G</div>
<div id='componentH'>H</div>
<div id='componentI'>I</div>
<div id='componentJ'>J</div>
<div id='componentK'>K</div>
<div id='componentL'>L</div>
</div>
<script src='componentA/script.js'></script>
<link rel='stylesheet' href='componentA/style.css'></link>
<script src='componentB/script.js'></script>
<link rel='stylesheet' href='componentB/style.css'></link>
<script src='componentC/script.js'></script>
<link rel='stylesheet' href='componentC/style.css'></link>
<script src='componentD/script.js'></script>
<link rel='stylesheet' href='componentD/style.css'></link>
<script src='componentE/script.js'></script>
<link rel='stylesheet' href='componentE/style.css'></link>
<script src='componentF/script.js'></script>
<link rel='stylesheet' href='componentF/style.css'></link>
<script src='componentG/script.js'></script>
<link rel='stylesheet' href='componentG/style.css'></link>
<script src='componentH/script.js'></script>
<link rel='stylesheet' href='componentH/style.css'></link>
<script src='componentI/script.js'></script>
<link rel='stylesheet' href='componentI/style.css'></link>
<script src='componentJ/script.js'></script>
<link rel='stylesheet' href='componentJ/style.css'></link>
<script src='componentK/script.js'></script>
<link rel='stylesheet' href='componentK/style.css'></link>
<script src='componentL/script.js'></script>
<link rel='stylesheet' href='componentL/style.css'></link>
</body>
</html>
Index.html do HTML Imports com recursos em linha
<!DOCTYPE html>
<html>
<head>
<style>
#layout {
width: 1024px;
height: 600px;
}
#layout > div {
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
</head>
<body>
<div id='layout'>
<div id='componentA'>A</div>
<div id='componentB'>B</div>
<div id='componentC'>C</div>
<div id='componentD'>D</div>
<div id='componentE'>E</div>
<div id='componentF'>F</div>
<div id='componentG'>G</div>
<div id='componentH'>H</div>
<div id='componentI'>I</div>
<div id='componentJ'>J</div>
<div id='componentK'>K</div>
<div id='componentL'>L</div>
</div>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentA {
backgroundimage: webkitlineargradient(top right,#FF0000, #FF0000);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentB {
backgroundimage: webkitlineargradient(top right, #FFFF00, #FFFF00);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentC {
backgroundimage: webkitlineargradient(top right, #00FF00, #00FF00);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentD {
backgroundimage: webkitlineargradient(top right, #00FF80, #00FF80);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentE {
backgroundimage: webkitlineargradient(top right,
#00FFFF, #00FFFF);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentF {
backgroundimage: webkitlineargradient(top right, #0080FF, #0080FF);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentG {
backgroundimage: webkitlineargradient(top right, #0000FF, #0000FF);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentH {
backgroundimage: webkitlineargradient(top right, #FF00FF, #FF00FF);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentI {
backgroundimage: webkitlineargradient(top right, #FF00FF, #FF00FF);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentJ {
backgroundimage: webkitlineargradient(top right, #FF007F, #FF007F);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentK {
backgroundimage: webkitlineargradient(top right, #808080, #808080);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
<script>
console.time('time');
// Uma média de 100 milisegundos para cada conjunto de instruções.
// Laços
var arr = new Array(120000);
arr.forEach(function (x) {
x;
});
// Append string vs Join array
var i = 0,
j = 0,
str = '',
arr = [],
w1 = 'brown',
w2 = 'jumped',
w3 = 'lazy';
var str;
var timesAppend = 37e4;
arr2 = ['Quick ', w1, ' fox ', w2, ' over the ', w3, ' dog. '];
for (j = 0; j < timesAppend; j++) {
arr.push.apply(arr, arr2);
}
arr.join('');
var timesFlooring = 265e4;
for (var i = 0; i < timesFlooring; i++) {
// Flooring um número
var num = 26.9;
num = Math.floor(num);
}
// new ou Object.create
var Klass = function() {};
Klass.prototype.a = function() {};
Klass.prototype.b = function() {};
Klass.prototype.c = function() {};
if (typeof Object.create !== 'function') {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
var timesNew = 141e4;
for (var i = 0; i < timesNew; i++) {
var object = Object.create(Klass.prototype);
}
// Testes
var lookupTable = {
'pizza': 'food',
'house': 'building',
'table': 'furniture',
'car': 'driving',
'water': 'drink',
'air': 'nothing'
};
var timesTest = 733e4;
for (var i = 0; i < timesTest; i++) {
lookupTable['pizza'];
lookupTable['water'];
lookupTable['air'];
}
console.timeEnd('time');
</script>
<style>
#componentL {
backgroundimage: webkitlineargradient(top right, #FF8000, #FF8000);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
</body>
</html>
Index.html do Shadow DOM não otimizado
<!DOCTYPE html>
<html>
<head>
<style>
#layout {
width: 1024px;
height: 600px;
}
#layout > div {
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
</style>
</head>
<body>
<div id='layout'>
</div>
<script>
var host = document.getElementById('layout');
var root = host.createShadowRoot();
</script>
<link rel='import' href='componentA/index.html'></link>
</body>
</html>
Style.css do componente com Shadow DOM não otimizado
#componentA {
backgroundimage: webkitlineargradient(top right, #FF0000, #FF0000);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
Index.html do Shadow DOM otimizado
<!DOCTYPE html>
<html>
<head>
<style>
#layout::shadow div {
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}
#layout {
width: 1024px;
height: 600px;
}
</style>
</head>
<body>
<div id='layout'>
</div>
<script>
var host = document.getElementById('layout');
var root = host.createShadowRoot();
</script>
<link rel='import' href='componentA/index.html'></link>
</body>
</html>
Style.css do componente com Shadow DOM otimizado
#componentA {
backgroundimage: webkitlineargradient(top right, #FF0000, #FF0000);
display: inlineblock;
width: 20%;
height: 33%;
textalign: center;
fontsize: 165px;
}