The Yahoo team has identified a number of best practices for making web pages fast. The list includes 35 best practices divided into 7 categories.
Translating YSlow rules has been made possible by the following contributors:
El 80% del tiempo de respuesta de una página web se emplea en las llamadas. La mayor parte de este tiempo se está vinculado a la descarga de todos los componentes en la página: imágenes, hojas de estilo, scripts, flash, etc. Reducir el número de componentes, a su vez, reduce el número de peticiones HTTP necesarias para visualizar la página. Esta es la clave fundamental de la rapidez de una página.
Una forma de reducir el número de componentes en la página es simplificar el diseño de la misma. Hay maneras de construir las páginas con el mismo diseño pero con menor número de peticiones HTTP, he aquí algunas técnicas para reducir el número de llamadas HTTP manteniendo un diseño rico.
La unión de archivos es una manera de reducir el número de peticiones HTTP mediante la combinación de todos los scripts en una única secuencia de comandos, y también la combinación de todos los CSS en una sola hoja de estilos. La combinación de los archivos es más difícil cuando los javascripts y las hojas de estilo varían de una página a otra, pero el proceso mejora los tiempos de carga.
Los CSS Sprites son un método de referencia para reducir el número de imágenes unificándolas. Combinando las imágenes de fondo con las propiedades background-position
y background-image
puedes mostrar trozos de una misma imagen haciendo que todas las imágenes principales de la web se llamen de una sola vez.
Los Image maps combinan varias imágenes en una. El tamaño total es de aproximadamente el mismo, pero la reducción del número de peticiones HTTP acelera la página. El mapa de imágenes sólo funcionará si las imágenes son contiguas, como una barra de navegación. La creación de un mapa de imágenes puede ser tedioso y propenso a errores. El uso de esta técnica no es recomendable para la navegación, elija CSS Sprites antes.
Imágenes, utilizar los datos: URL scheme, incrustar los datos:
URL scheme de la imagen en la página real. Esto puede aumentar el tamaño de su documento HTML. La combinación de imágenes (en caché), las hojas de estilo es una manera de reducir las peticiones HTTP y evitar el aumento del tamaño de sus páginas. Las imágenes aún no se han apoyado en todos los principales navegadores.
Reducir el número de peticiones HTTP de su web es muy efectivo. Esta es la norma más importante para mejorar el rendimiento de los visitantes, que acceden por primera vez a la página web. Contenido.
La proximidad del usuario a su servidor web tiene un impacto sobre los tiempos de respuesta. El despliegue de su contenido a través de múltiples servidores dispersos geográficamente hará que sus páginas se carguen más rápido desde la perspectiva del usuario. Pero ¿por dónde debe empezar?
Como primer paso para aplicar esta técnica, no intente rediseñar su aplicación web para trabajar en una arquitectura distribuida. Dependiendo de la aplicación, la modificación de la arquitectura podría incluir enormes tareas como la sincronización del estado de la sesión y replicar la base de datos del servidor a través de transacciones de lugares. Los intentos de reducir la distancia entre los usuarios y su contenido podría retrasarse, o no llegar nunca a los usuarios, esta aplicación es una etapa de la arquitectura.
Recuerde que el 80-90% de los visitantes pierden tiempo mientras se descargan todos los componentes en la página: imágenes, hojas de estilo, scripts, Flash, etc. Ésta es la la regla de oro del rendimiento. En lugar de comenzar con la tediosa prática de rediseñar la arquitectura de su aplicación, es mejor desplegar primero el contenido estático. Ésto, aparte de conllevar una fantástica reducción del tiempo de descarga, se facilita gracias a las Content Delivery Network.
Un Content Delivery Network (CDN) o Red de distribución de contenido, en español, es un grupo de servidores web distribuidos en varias ubicaciones para ofrecer contenidos de manera más eficiente a los usuarios. El servidor seleccionado para la entrega de contenido a un usuario concreto es típicamente basado en una medida de aproximación. Por ejemplo, el servidor con el menor número de saltos o el servidor con más rápida respuesta es el elegido.
Algunas empresas poseen sus propias CDN, dado que es menos costoso que usar un proveedor del servicio. Para los sitios web de pequeñas empresas públicas o privadas, el costo del servicio CDN puede ser prohibitivo, pero dado que su objetivo principal es crecer y abarcar cada vez más audiencia, una CDN es necesaria para lograr una rápida respuesta. El cambio a una CDN es relativamente fácil, lo que mejorará dramáticamente la velocidad de su sitio web.
Esta norma tiene dos sencillos objetivos:
Expires
Header para las próximas visitas.Cache-Control
Header mas apropiado para ayudar al navegador en las llamadas HTTP.Los diseños de las páginas web se enriquecen cada vez más, lo cual representa más scripts, hojas de estilo, imágenes y animaciones Flash en el contenido. Una visita por primera vez a la página puede contener muchas llamadas HTTP, pero usando un Header Expires permitirá que esos componentes se guardan en la cache. Esto evita llamadas HTTP innecesarias en subsecuentes visitas. Los Expires Headers se usan muy a menudo con las imágenes, pero se debería usar con todos los componentes incluyendo scripts, hojas de estilo y animaciones Flash.
Los navegadores (y proxies) usan la caché para reducir el número y el tamaño de las peticiones HTTP, permitiendo que la página web cargue más rápido. Un servidor web utiliza las Expires Header en las respuestas HTTP para comunicarle al cliente cuánto tiempo puede estar un componente en la caché. Ésta es una Expires Header con mucha duración, diciéndole al navegador que esta respuesta no caducará hasta el 15 de Abril del 2010.
Expires: Thu, 15 Apr 2010 20:00:00 GMT
Si tu servidor es Apache, use la directiva ExpiresDefault para determinar una fecha de expiración relativa a la fecha actual. Este ejemplo de la directiva ExpiresDefault establece la fecha de expiración a 10 años a partir del momento de la petición.
ExpiresDefault "access plus 10 years"
Recuerda, si usas una Expires header con mucha duración, debes cambiar el nombre del archivo del componente cada vez que lo modifiques.
Usando una Expires header de larga duración, sólo afecta a las páginas vistas después de que un usuario ha visitado su sitio. No tiene ningún efecto en el número de peticiones HTTP cuando un usuario visita su sitio por primera vez y la caché del navegador está vacía. Por lo tanto, la mejora del rendimiento depende en medida de la frecuencia en que sus usuarios visitan sus páginas con una primed cache. (Una “primed cache” ya contiene la totalidad de los componentes en la página.) El usar una Expires header de larga duración, le incrementará el número de componentes que son cacheables por el navegador y reutilizarlos en posteriores visitas a la página, sin necesidad de enviar un solo byte al cliente.
El tiempo que le toma transferir una petición HTTP y su respuesta a través de la red pueden ser reducirse significativamente por las decisiones tomadas por los ingenieros en el “front-end”. Es cierto que el ancho de banda, proveedor de Internet, proximidad a los puntos de intercambio, etc. del usuario, están fuera del control del equipo de desarrollo. Pero hay otras variables que afectan los tiempos de respuesta. La compresión reduce los tiempos de respuesta al reducir el tamaño de las peticiones HTTP.
A partir de HTTP/1.1, los navegadores web permiten el soporte para compresión con la cabecera Accept-Encoding en la petición HTTP.
Accept-Encoding: gzip, deflate
Si el servidor web visualiza esta cabecera en la petición, puede comprimir la respuesta usando uno de los métodos listados por el client. El servidor web notifica al cliente a través de la cabecera Content-Encoding en la respuesta.
Content-Encoding: gzip
Gzip es el método más popular y efectivo de compresión en este momento. El mismo fue desarrollado por el proyecto GNU y estandarizado por RFC 1952. El otro formato de compresión que puede usar es Deflate, pero es menos efectivo y menos popular.
Comprimiendo con Gzip generalmente reduce el tamaño de la respuesta hasta en un 70%. Aproximadamente el 90% del tráfico en Internet hoy en día viaja a través de los navegadores que especifican el soporte para Gzip. Si usas Apache, el módulo de configuración de Gzip depende de la versión: Apache 1.3 usa mod_gzip mientras que Apache 2.x usa mod_deflate.
Existen problemas conocidos con navegadores y proxies que pueden causar un desequilibrio en lo que el navegador espera y lo que recibe en relación con el contenido comprimido. Afortunadamente, estos casos están disminuyendo dado que el uso de navegadores antiguos también disminuye Los módulos de Apache ayudan añadiendo las cabeceras apropiadas automáticamente.
Los servidores escogen qué comprimir, basado en el tipo de archivo, pero suelen ser muy limitados en lo que deciden comprimir. Muchos sitios web comprimen sus documentos HTML. También es recomendable comprimir sus scripts y hojas de estilo, pero muchos sitios web desaprovechan esta cualidad. De hecho, es útil comprimir cualquier texto incluyendo respuestas XML y JSON. Las imágenes y los documentos PDF no deben ser tratados con Gzip ya que estos ya están comprimidos. Intentar hacerlo no sólo desperdicia recursos del CPU, sino que incrementan el tamaño del archivo.
Tratar con Gzip cuanto tipo archivo sea posible, es una excelente manera de reducir el peso de la página y acelerar la carga para el usuario.
Tras bastidores, los ingenieros se preocupan por el rendimiento deseado en una página de carga progresiva; eso es, nosotros queremos desplegar en el navegador cualquier contenido lo más pronto posible. Ésto es especialmente importante en páginas con mucho contenido con usuarios con una conexión lenta.
La importancia de proporcionar a los usuarios información visual, tales como indicadores de progreso, ha sido bien investigada y documentada. En nuestro caso la misma página HTML es el indicador de progreso! Cuando el navegador carga la página, aparece progresivamente la cabecera, la barra de navegación, el logotipo en la parte superior, etc. sirven como retroalimentación visual para el usuario que está a la espera. Esto mejora la experiencia del usuario.
El problema de poner las hojas de estilo en la parte inferior del documento es que se anula la carga progresiva en muchos navegadores como Internet Explorer. Estos navegadores bloquean el renderizado para evitar tener que redefinir los elementos de la página si sus estilos cambian, el usuario estaría recibiendo una página en blanco.
La Especificación HTML establece claramente que las hojas de estilo se incluirán en la sección HEAD de la página: “A diferencia de A, [LINK] sólo pueden aparecer en la sección HEAD de un documento, aunque puede aparecer cualquier número de veces.” Ninguna de las alternativas, la pantalla en blanco o las animaciones flash sin estilos, valen la pena arriesgarse. La solución óptima es seguir la especificación HTML y cargar sus hojas de estilo en el HEAD.
El problema causado por los scripts, es que bloquean las descargas paralelas. La especificación HTTP/1.1 sugiere que los navegadores descarguen no más de dos componentes en paralelo por servidor. Si usted sirve sus imágenes desde múltiples servidores, usted puede tener más de dos descargas que se produzcan en paralelo. Mientras un script está descargándose, sin embargo, el navegador no iniciará otra descarga, incluso de diferentes servidores.
En algunas situaciones no es fácil mover los scripts al fondo. Si, por ejemplo, el script utiliza document.write
para insertar contenido en la página, no se lo puede mover más abajo. También podrían haber problemas de alcance. En muchos casos, hay formas de solucionar estas situaciones.
Una sugerencia alternativa que a menudo surge es utilizar scripts en diferido. El atributo DEFER
indica que el scriptno contiene document.write, y es una pista para los navegadores para que ellos puedan continuar trabajando.
Desafortunadamente, Firefox no soporta el atributo DEFER
. En Internet Explorer, el script se lo puede diferir, pero no tanto como se desea. En caso de que un script pueda ser diferido, también puede ser trasladado a la parte inferior de la página. Que hará que sus páginas web se carguen más rápido.
Las expresiones CSS son una poderosa (y peligrosa) manera de establecer propiedades CSS dinámicamente. Están soportadas por Internet Explorer, desde la versión 5. Como por ejemplo, el color de fondo puede ser alternado cada hora usando expresiones CSS.
background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
Como se muestra aquí, el método expresión
acepta una expresión JavaScript. La propiedad CSS se establece en el resultado de la evaluación de la expresión JavaScript. El método expresión es ignorado por otros navegadores, por lo que es útil para ajustar las propiedades de Internet Explorer necesarias para crear una experiencia consistente a través de navegadores.
El problema con las expresiones que son evaluadas más frecuentemente de lo que la mayoría de la gente espera. No sólo son evaluadas cuando la página se renderiza y redimensiona, sino que además cuando la página es navegada e incluso cuando el usuario mueve el cursor del ratón sobre la misma. Añadir un contador a la expresión CSS nos permite monitorear cuándo y como una expresión CSS es evaluada. Moviendo el cursor del ratón alrededor de la página puede fácilmente generar más de 10.000 evaluaciones.
Una forma de reducir el número de veces en que son evaluadas tus expresiones CSS es usar una sola vez las expresiones, donde la primera vez en que la expresión se evalúa se establece el estilo de propiedad a un valor explícito, que sustituye a la expresión CSS. Si el estilo de propiedad debe ser dinámico durante toda la vida útil de la página, se puede enfocar una alternativa con eventos en lugar de las expresiones CSS. Si es irreversible el utilizar expresiones CSS, recuerde que pueden ser evaluadas en miles de veces y podría afectar el rendimiento de su página.
For front pages that are typically the first of many page views, there are techniques that leverage the reduction of HTTP requests that inlining provides, as well as the caching benefits achieved through using external files. One such technique is to inline JavaScript and CSS in the front page, but dynamically download the external files after the page has finished loading. Subsequent pages would reference the external files that should already be in the browser’s cache.
Muchas de estas reglas de rendimiento refieren sobre cómo son gestionados los componentes externos. Sin embargo, antes de estas consideraciones debería hacerse una pregunta básica: Deberían el código JavaScript y los estilos CSS estar contenidos en ficheros externos, o introducidos en la propia página?
El usar ficheros externos generalmente produce una carga rápida del documento, ya que el código JavaScript y los archivos CSS son guardados en el caché del navegador. Los códigos JavaScript y CSS que están embebidos en el documento HTML son descargados cada vez que el documento HTML es llamado. Esto reduce el número de peticiones HTTP, pero incrementa el tamaño del documento HTML. Por otro lado, si el código JavaScript y CSS están en archivos externos cacheados por el navegador, el tamaño de el documento HTML es reducido sin incrementar el número de llamadas HTTP.
El factor clave, entonces, es la frecuencia con la que el archivo externo JavaScript y CSS son cacheados en relación al numero de documentos HTML llamados. Este factor, aunque difícil de cuantificar, se puede medir utilizando diversos. Si los usuarios en su sitio tienen varias páginas vistas por sesión y muchas de sus páginas reutilizarán los scripts y hojas de estilo, hay un mayor beneficio de los archivos externos guardados en caché.
Muchos sitios web se enredan en medio de estos parámetros. Para estos sitios, la mejor solución generalmente es desarrollar el código JavaScript y CSS en archivos externos. La única excepción en donde el código embebido es recomendable es en las páginas de inicio. Las páginas de inicio que tienen pocas (por no decir sólo una) visita por sesión pueden encontrar que embebiendo el código JavaScript y CSS resulta en una respuesta más rápida.
Para las páginas de inicio que son comúnmente la primera página vista, hay que aprovechar el embebido como una técnica de reducción de peticiones HTTP, así como el beneficio obtenido mediante el almacenamiento en caché de los archivos externos. Una de estas técnicas es embeber javascript y CSS en la página de inicio, salvo descargar dinámicamente los archivos externos luego de que la página ha terminado de cargar. Las páginas de referencia a los archivos externos deberían estar ya en la caché del navegador.
Cuando usted escribe www.midominio.com en su navegador, una resolución de DNS en contacto con el navegador, devuelve la dirección IP del servidor. El DNS tiene un costo. Que generalmente es de 20-120 milisegundos por DNS para encontrar la dirección IP de un hostname dado. El navegador no puede descargar nada de este hostname hasta que la búsqueda DNS se haya completado.
Las búsquedas DNS son cacheadas para mejor rendimiento. Este cacheo puede acontecer en un servidor especial de caché, mantenido por el usuario del ISP o red de área local, pero también está el cacheo que ocurre en la computadora individual de cada usuario. La información DNS queda en el caché de DNS del Sistema Operativo (el “DNS Client service” en Microsoft Windows). Muchos navegdores tienen sus propias caches, separadas de la caché del sistema operativo. En la medidad en que el navegador guarda un registro DNS en su propia caché, ello no infiere al sistema operativo con una petición de ese registro.
Internet Explorer almacena en caché las búsquedas DNS por 30 minutes por defecto, especificado la entrada del registro DnsCacheTimeout
. Firefox cachea las búsquedas DNS por 1 minuto, controlada por la opción network.dnsCacheExpiration
en la configuración del navegador. (Fasterfox cambia esto a 1 hora.)
Cuando la caché DNS del cliente está vacía (tanto en el navegador como en el sistema operativo), el número de búsquedas DNS es igual al número de hostname únicos en la página web. Esto incluye los hostnames usados en la página URL, imágenes, archivos de script, hojas de estilo, animaciones Flash, etc. Reduciendo el número hostnames únicos se reduce el número de búsquedas DNS.
Reduciendo el número de hostname únicos tiene el potencial de reducir la cantidad de descargas parlelas que toman a lugar en la página. Evitando búsquedas DNS acorta los tiempos de respuesta, pero reduciendo las descargas paralelas puede aumentarlos. Mi preferencia es dividir estos componentes a través de al menos dos, pero no m´s de cuatro hostnames. Esto resulta en un buen compromiso entre reducir las búsquedas DNS y permitir un alto grado de descargas paralelas.
Minimización es la práctica de eliminar el código de caracteres innecesarios para reducir su tamaño, mejorando así los tiempos de carga. Cuando el código es minimizado todos los comentarios se eliminan, así como los espacios en blanco y caracteres innecesarios (espacio, nueva línea…). En el caso de JavaScript, esto mejora el tiempo de respuesta de rendimiento debido a que el tamaño del archivo descargado es reducido.
La ofuscación es una alternativa de optimización que se pueden aplicar al código fuente. Es más complejo que la minimización y, por tanto, más posibilidades de generar errores. En una encuesta de los diez principales sitios web de EE.UU., la minimización alcanzó un 21% la reducción de tamaño frente a un 25% de la ofuscación. A pesar de la ofuscación tiene mayor reducción de tamaño, minificar JavaScript es menos arriesgado.
Incluso si usted comprime con gzip sus archivos javascript y de estilo, minimizarlos podría reducir el tamaño en un 5% o más.
Las redirecciones web se consiguen utilizando los códigos de estado 301 y 302. He aquí un ejemplo de las cabeceras HTTP 301 en una respuesta:
HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html
El navegador automáticamente lleva al usuario a la página especificada en el campo Location
. Toda la información necesaria para el redireccionamiento está en el encabezado. A pesar de sus nombres, ni un archivo con 301 ni uno con 302 es cacheado en la práctica a menos que tenga otras cabeceras, como Expires
o Cache-Control
. La etiqueta meta refresh y JavaScript son otras formas de dirigir a los usuarios a una URL diferente, pero si usted tiene que hacer un redireccionamiento, la técnica preferida es utilizar el estándar de códigos de estado HTTP 3xx, principalmente para garantizar que el botón Atrás funciona correctamente.
Lo principal a recordar es que redirecciones frenan la experiencia del usuario. La utilización de un redireccionamiento obliga al navegador a buscar nuevamente la página web perdiendo un tiempo, a veces, notable.
Uno de los errores mas comunes de los desarrolladores y programadores web es colocar urls a una carpeta sin la diagonal al final (/). Por ejemplo, si usted enlaza http://astrology.yahoo.com/astrology desde su sitio web verá que le agrega automáticamente “/” al final, dejándola así; http://astrology.yahoo.com/astrology. Esto se fija en Apache utilizando Alias
o mod_rewrite
, o la directiva DirectorySlash si estás usando Apache handlers.
Conectar un sitio web viejo con uno nuevo es otra práctica común para redirecciones. Otras incluyen conectar diferentes partes de sitios weby redireccionar al usuario basándose en ciertas condiciones (tipo de navegador, tipo de cuenta de usuario, etc). Usar una redirección para conectar dos sitios web es simple y requiere poco código adicional. Aunque usando redirecciones en estas situaciones reduce la complejidad para los desarrolladores, ello disminuye la experiencia del usuario. Alternativas para esto incluyen el uso de redirecciones usando Alias y mod_rewrite si las dos rutas físicas del código están alojadas en el mismo servidor. Si un cambio del nombre de dominio es la causa del uso de redirecciones, una alternativa es crear un CNAME (un registro DNS que crea un alias apuntando desde uno de los dominios a otro) en combinación con Alias
o mod_rewrite
.
Cómo afecta al rendimiento incluir el mismo javascript dos veces en una misma página. Esto no es tan inusual como se cree. Una revisión del top 10 de los sitios de EE.UU. revela que dos de ellos contienen scripts duplicados. Hay dos principales factores que incrementan las probabilidades de que un script esté duplicado en una página web: tamaño del equipo y el número de scripts. Cuando esto ocurre, los scripts duplicados afectan el rendimiento creando peticiones HTTP innecesarias y desperdicia la ejecución del javascript.
Las llamadas HTTP innecesarias ocurren en Internet Explorer, mas no en Firefox. En Internet Explorer, si un script externo es incluido dos veces y no es cacheable, ello genera dos llamadas HTTP durante la carga de la página. Incluso si el script es cacheable, las peticiones extra ocurren cuando el usuario recarga la página.
Además de generar un torrente de peticiones HTTP, se pierde tiempo evaluando el script varias veces. Esta redundancia en la ejecución del Javascript ocurre tanto en Firefox como en Internet Explorer, independientemente de que el script sea o no caheable.
Una solución para evitar accidentalmente incluir dos veces el mismo guión dos veces es implementar un módulo administrador de scripts en su sistema de plantillas. La forma más común de incluir un script es mediante el uso de la etiqueta SCRIPT en su página HTML.
<script type="text/javascript" src="menu_1.0.17.js"></script>
Una alternativa en php podría ser crear una función llamada insertScript.
<?php insertScript("menu.js") ?>
En adición, para prevenir que el mismo script sea insertado varias veces, esta función debería manejar otros temas con los scripts, tales como añadir el número de versión al nombre del archivo para soportar Expires headers de larga duración.
Entity tags (ETags) son un mecanismo que servidores y navegadores usan para determinar si el componente guardado en la caché del navegador coincide con el del servidor de origen. (Una “entidad” es otra palabra, un “componente”: imágenes, scripts, hojas de estilo, etc.) las ETags se han creado para proveer un mecanismo para validar entidades, que es más flexible que la fecha de modificación. Una ETag es una cadena que identifica de forma exclusiva una versión específica de un componente. El servidor de origen especifica el componente usando la cabecera ETag
.
HTTP/1.1 200 OK
Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
ETag: "10c24bc-4ab-457e1c1f"
Content-Length: 12195
Luego, si el navegador tiene que validar un componente, utiliza la cabecera If-None-Match
para traspasar la ETag de regreso al servidor de origen. Si la ETag enviada, devuelve un código 304 es retornada reduciendo la respuesta en 12195 bytes para este ejemplo.
GET /i/yahoo.gif HTTP/1.1
Host: us.yimg.com
If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
If-None-Match: "10c24bc-4ab-457e1c1f"
HTTP/1.1 304 Not Modified
El problema con las ETags es que generalmente se construyen utilizando los atributos que la hacen única para un determinado sitio alojado en el servidor. Las ETags no coincidirán cuando un navegador obtiene el componente original de un servidor y luego intenta validar ese componente en un servidor distinto, una situación que es muy común en sitios web que usan un grupo de servidores para manejar las peticiones. Por defecto, tanto Apache como IIS embeben datos en la ETag que reducen drásticamente las posibilidades de éxito en la prueba de validez en sitios web con múltiples servidores.
El formato de la ETag para Apache 1.3 y 2.x es inode-size-timestamp
. Aunque un determinado archivo puede estar en el mismo directorio a través de múltiples servidores, y tener el mismo tamaño, permisos, fecha, etc., su Inodo es diferente de un servidor a otro.
IIS 5.0 y 6.0 tienen un problema similar con las ETags. El formato para las ETags en IIS es Filetimestamp:ChangeNumber
. Un ChangeNumber
es un contador utilizado para realizar un seguimiento track de los cambios en la configuración de IIS. Es poco probable que el ChangeNumber
sea el mismo en todos los sitios web alojados en un servidor IIS.
El resultado final es un ETags generado por Apache e IIS para el mismo componente no coincidirá de un servidor a otro.Si las ETags no coinciden, el usuario no recibe la pequeña respuesta 304 que las ETags han diseñado; en cambio, se obtendrá unas 200 respuestas normales con todos los datos del componente. Si usted aloja su sitio web en un solo servidor, esto no es un problema. Pero si usted tiene múltiples servidores para alojar su sitio web, y está usando Apache o IIS con la configuración predeterminada de las ETag, sus usuarios estarán ante páginas cada vez más lentas, sus servidores tendrán una sobrecarga, estará consumiendo mucho ancho de banda, y los proxies no estarán caheando el contenido eficientemente. Incluso si sus componentes tienen una Expires header
de larga duración, una solicitud GET condicional sigue siendo realizada siempre que el usuario presione Recargar o Refrescar.
Si usted no está tomando ventaja de la flexibilidad que proporciona el modelo de validación de las ETags, es mejor que simplemente retire la ETag completamente. La cabecera Last-Modified
header valida sobre la base de marca de tiempo del componente. Y la eliminación de la ETag reduce el tamaño de las cabeceras HTTP, tanto en la respuesta como en las solicitudes posteriores. En Apache es realmente sencillo, solo debemos añadir la siguiente línea, en nuestro archivo de configuración de Apache:
FileETag none
Uno de los beneficios citados de Ajax es que provee de información visual instantánea al usuario, porque la información es traída asíncrona desde el backend del servidor web. Sin embargo, el uso de Ajax no garantiza que el usuario no se rascará la cabeza esperando el retorno de las respuestas Asíncronas de Javascript y XML. En muchas aplicaciones, independientemente de si el usuario se mantendrá o no en espera depende de cómo se utiliza Ajax. Por ejemplo en un cliente de correo basado en web, el cliente se mantendrá en espera de los resultados de una petición Ajax para encontrar todo los mensajes de correo electrónico que coincidan con sus criterios de búsqueda. Es importante recordar que”asíncrono” no implica que sea “instantáneo”.
Para mejorar el rendimiento, es importante optimizar esas repuestas Ajax. La manera más importante para mejorar el rendimiento de Ajax es hacer que esas respuestas sean cacheables como se discutió en Agregar Expires o Cache-Control Header.
Veamos un ejemplo. Un cliente de correo basado en web 2.0, puede usar Ajax para descargar la libreta de direcciones del usuario para realizar un autocompletado. Si el usuario no ha modificado su libreta de direcciones desde la última vez que el usuario usó la aplicación, la anterior libreta de direcciones podría ser leída desde la caché si esa respuesta Ajax fue hecha cacheable con una cabecera Expires o Cache-Control de larga duración. El navegador debe ser informado de cuándo utilizar una libreta de direcciones guardada en caché versus solicitar una nueva. Esto podría hacerse mediante la adición de una fecha a la libreta de direcciones indicando la última vez que el usuario modificó su libreta de direcciones, por ejemplo &t=1190241612
. Si la libreta de direcciones no ha sido modificada desde la última descarga, la fecha deberá ser la misma y la libreta de direcciones será leída desde la cache del navegador eliminando una petición HTTP extra. Si el usuario ha modificado su libreta de direcciones, la fecha indica que la nueva URL no se asemeja a la respuesta guardada, así el navegador solicitará las entradas actualizadas.
Aunque sus respuestas Ajax responses sean creadas dinámicamente, y pueden ser aplicables a un usuario en particular, aún pueden ser cacheadas. Haciendo así, hará que sus aplicaciones Web 2.0 apps sean más rápidas.
Cuando los usuarios solicitan una página, se puede tomar de 200 a 500 milisegundos para el servidor crear el código html. Durante este tiempo, el navegador está inactivo ya que espera la llegada de los datos. En PHP tienes la función flush(). La que te permite enviar una respuesta HTML parcialmente lista al navegador así el navegador puede comenzar a buscar los componentes mientras que en el fondo está ocupado con el resto de la página HTML. El beneficio se encuentra principalmente en fondos ocupados o portadas ligeras.
Un buen lugar para considerar esto es inmediatamente después de la cabecera, es generalmente más fácil de producir y permite incluir cualquier cualquier archivo CSS o Javascript para que el navegador comience a buscar en paralelo mientras en el fondo está aun procesando.
Ejemplo:
... <!-- css, js -->
</head>
<?php flush(); ?>
<body>
... <!-- content -->
Yahoo! search pioneered research and real user testing to prove the benefits of using this technique.
El equipo de Yahoo! Mail que cuando se usaba XMLHttpRequest
, el POST es implementado en los navegadores en un proceso de dos pasos: enviando las cabeceras primero, luego se envían los datos. Por lo tanto es mejor usar GET, el cual solo envía un paquete (a menos que tengas un montón de cookies). La longitud máxima en Internet Explorer es de 2kb, de modo que si necesitas enviar mas de 2kb no será capaz de usar GET.
Un lado interesante es que el envío mediante POST sin ningún dato, hace que se comporte como GET. Basado en las especificaciones HTTP, GET es para recuperar la información, así tiene sentido (semánticamente) el usar GET sólo para la solicitudes de datos, a diferencia del envío de datos para ser guardados en el servidor.
Usted puede ver más de cerca su página y preguntarse: “Qué es absolutamente necesario para crear la página de inicio?”. El resto del contenido y los componentes pueden esperar.
JavaScript es un candidato ideal para dividir antes y después del evento onload. Por ejemplo si usted tiene el código y las librerías necesarias para hacer un “arrastrar y soltar” y animaciones, esos pueden esperar porque el arrastre de los elementos en la página vienen después del renderizado inicial. Otros lugares que lucen como candidatos para el post-loading incluyen el contenido oculto (contenido que aparece luego de una acción del usuario) y las imágenes ocultas.
Tools to help you out in your effort: YUI Image Loader allows you to delay images below the fold and the YUI Get utility is an easy way to include JS and CSS on the fly. For an example in the wild take a look at Yahoo! Home Page with Firebug’s Net Panel turned on.
Es bueno cuando se obtienen los resultados deseados con otras prácticas de desarrollo web. En este caso, la idea de la progresiva mejora de Javascript nos dice que, cuando cuentan con el soporte, pueden mejorar la experiencia del usuario, pero debe asegurarse de que la página igualmente funcione sin javascript. Así, luego de que usted se haya cerciorado que la página funciona correctamente, usted puede mejorarla con algunos scripts para acicalarla con funcionalidades como el arrastrar y soltar y animaciones.
El Preload o precarga puede parecer lo opuesto a la Post-load o carga posterior, pero actualmente tiene una meta distinta. Por precargar componentes usted puede tomar ventaja del tiempo en que el navegador está inactivo y así pedir los componentes (como imágenes, estilos y scripts) que necesitará en el futuro. De esta manera cuendo el usuario visite la página siguiente, usted podría tener muchos de los componentes ya en la caché del navegador y la página le cargará mucho más rápido al usuario.
Aquí hay varios tipos de precarga:
Una página compleja quiere decir muchos bytes para descargar y además supone un lento acceso al DOM en Javascript. Ello denota la diferencia si usted repite a través de 500 o 5000 elementos DOM en la página cuando quiera añadir un manejador de eventos por ejemplo.
Un alto número de elementos DOM puede ser un síntoma de que hay algo que debe ser mejorado con la marcación de la página sin la necesidad de afectar o remover el contenido. Está usted usando tablas anidadas con fines de diseño? Está usted creando <div>
solo para fijar problemas de diseño? Tal vez hay una mejor forma de hacer sus marcados más semánticamente.
Esta es una oportunidad para comenzar de nuevo y pensar sobre el marcado, Por ejemplo el uso de
Encontrar el número de elementos DOM es sencillo, solo escriba en la consola de Firebug:
document.getElementsByTagName('*').length
¿Y cuántos elementos DOM se consideran como demasiados? Compruebe otras páginas similares que tienen un buen marcado. For example the Yahoo! Home Page is a pretty busy page and still under 700 elements (HTML tags).
Dividir los componentes le permite maximizar las descargas paralelas. Asegúrese de que no está usando más de 2-4 dominios porque las búsquedas DNS le penalizarán. Por ejemplo, usted puede alojar su HTML y el contenido dinámico en www.midominio.com y dividir los componentes estáticos entre static1.example.org
y static2.example.org
For more information check “Maximizing Parallel Downloads in the Carpool Lane” by Tenni Theurer and Patty Chi.
Los Iframes permiten que un documento HTML sea insertado en un documento padre. Es importante entender cómo trabajan los iframes para que puedan ser usados eficazmente.
<iframe>
pros:
<iframe> contras:
Las peticiones HTTP son costosas, de modo que hacer una petición HTTP y no obtener un resultado (ej. error 404 Not Found) son totalmente innecesarias y ralentizarán la experiencia del usuario sin ningún beneficio.
Algunos sitios tienen páginas 404 con contenido útil “¿Quizá está buscando X?”, lo cual es ideal para la experiencia del usuario, pero además representan un desperdicio de recursos del servidor (como la base de datos, etc.). Es particularmente malo cuando el enlace a un javascript externo falla y ello deriva en una página 404. Primero, esta descarga bloqueará las demás descargas paralelas. Luego el navegador tratará de interpretar el cuerpo de la respuesta 404 como si fuera el mismo código javascript, intentando hallar algo usable en él.
Acceder a elementos DOM con JavaScript es lento con el fin de tener una mejor capacidad de respuesta, usted debería:
For more information check the YUI theatre’s “High Performance Ajax Applications” by Julien Lecomte.
Algunas veces las páginas tienen menos respuesta a cada uno de los manejadores de eventos adjuntados a diferentes elementos del árbol DOM, los cuales son ejecutados con demasiada frecuencia. Esa es la razón por la que usar delegación de eventos es una buena práctica. Si tienes 10 botones dentro de un div
, conecte un solo evento a la capa, en lugar de un manejador para cada botón. Englobe los eventos, de modo que usted pueda encontrar el evento y averiguar de qué botón se originó.
Además no es necesario esperar a la carga del evento para comenzar a hacer algo con el árbol DOM. A menudo todo lo que se necesita es que elemento al cual quiere acceder esté disponible en el árbol. Usted no necesita esperar a a que todas las imágenes se hayan descargado. El DOMContentLoaded
es el evento que usted puede usar e lugar de onload.
For more information check the YUI theatre’s “High Performance Ajax Applications” by Julien Lecomte.
Una de las mejores prácticas de la categoría CSS explica el porqué deben llamarse las hojas de estilo en el encabezado, con el fin de permitir la carga progresiva.
En Internet Explorer el código @import
se comporta de la misma forma que el código <link>
desde la parte inferior de la página, por lo que no se debe usar.
El filtro propietario de IE AlphaImageLoader
tiene por objeto solucionar un problema con PNGs semi transparentes true-color en las versiones de IE inferiores a la 7. El problema con este filtro es que bloquea el renderizado y congela el navegador mientras la imagen está siendo descargada. Esto además incrementa el consumo de memoria y es aplicado por elemento, no por imagen, de modo que el problema se multiplica.
El mejor enfoque es evitar el uso de AlphaImageLoader
completamente y usar en su reemplazo PNG8 con degradado, lo cual se ve bien en IE. Si usted necesita irremediablemente el uso de AlphaImageLoader
, use el truco de relieve _filter que no afecta a los usuarios de ie7.
Después de que un diseñador termina con la creación de las imágenes de tu sitio web, hay algunas cosas que usted puede probar antes de subir esas imágenes por FTP a su servidor.
identify -verbose image.gif
. Cuando vea una imagen que usa 4 colores y una paleta de 256, es idónea para mejorarla.convert image.gif image.png
“Lo que estamos diciéndole es: Déle una oportunidad a los PNGs!”pngcrush image.png -rem alla -reduce -brute result.png
jpegtran -copy none -optimize -perfect src.jpg dest.jpg
No use una imagen más grande de la que necesita, simplemente por que usted puede ajustar el ancho y el alto en HTML. Si usted necesita <img width="100" height="100" src="mycat.jpg" alt="My Cat" />
entonces su imagen (mycat.jpg) debería ser una imagen mayor de 500 x 500 px reducida a 100 x 100 px.
La favicon.ico es una imagen que se almacena en la raíz de tu servidor. Ésta es un mal necesario, porque aunque usted no le tenga ciudado, el navegador siempre va a pedirla, por lo que es mejor no responder con un 404 Not Found
. Además desde el hecho de que está en el mismo servidor, las cookies son enviadas cada vez que es pedida. Esta imagen también interfiere con la secuencia de descargas , por ejemplo en IE cuando usted pide componentes extra en la carga, la favicon será descargada antes que esos componentes.
Por lo tanto para mitigar los inconvenientes de tener una favicon.ico primero asegúrese de que:
Imagemagick can help you create small favicons
Esta restricción está relacionada con el hecho de que el iPhone no cachea componentes mayores de 25K. Tenga en cuenta que este es el tamaño descomprimido. Es importante aclararlo porque la compresión de los archivos no puede solucionar esto.
For more information check “Performance Research, Part 5: iPhone Cacheability - Making it Stick” by Wayne Shea and Tenni Theurer.
Embalar los documentos en un archivo es como un mensaje de correo electrónico con archivos adjuntos, le ayudará a obtener varios archivos en una sola petición HTTP, haciendo valer la primera regla de YSlow. Para utilizar esta norma antes debes verificar que el teléfono móvil admita este tipo de técnica.
To be translate. You can help. Please fork and edit…
Image with empty string src attribute occurs more than one will expect. It appears in two form:
<img src="">
var img = new Image();
img.src = "";
Both forms cause the same effect: browser makes another request to your server.
Why is this behavior bad?
The root cause of this behavior is the way that URI resolution is performed in browsers. This behavior is defined in RFC 3986 - Uniform Resource Identifiers. When an empty string is encountered as a URI, it is considered a relative URI and is resolved according to the algorithm defined in section 5.2. This specific example, an empty string, is listed in section 5.4. Firefox, Safari, and Chrome are all resolving an empty string correctly per the specification, while Internet Explorer is resolving it incorrectly, apparently in line with an earlier version of the specification, RFC 2396 - Uniform Resource Identifiers (this was obsoleted by RFC 3986). So technically, the browsers are doing what they are supposed to do to resolve relative URIs. The problem is that in this context, the empty string is clearly unintentional.
HTML5 adds to the description of the tag’s src attribute to instruct browsers not to make an additional request in section 4.8.2:
The src attribute must be present, and must contain a valid URL referencing a non-interactive, optionally animated, image resource that is neither paged nor scripted. If the base URI of the element is the same as the document’s address, then the src attribute’s value must not be the empty string.
Hopefully, browsers will not have this problem in the future. Unfortunately, there is no such clause for <script src="">
and <link href="">
. Maybe there is still time to make that adjustment to ensure browsers don’t accidentally implement this behavior.
This rule was inspired by Yahoo!’s JavaScript guru Nicolas C. Zakas. For more information check out his article “Empty image src can destroy your site”.