¿Cansado de esperar más de 5 segundos para que se visualice la página de un blog? ¿agobiado de esos sitios con decenas de widgets, gadgets, efectos AJAX y mashups que tardan horas en cargarse? ¿amargado porque has desarrollado un programa muy eficiente para el último framework de moda y «va lento»? Yo también, y me molesta mucho, considero que son chapuzas increíbles que no tienen en cuenta lo básico de la usabilidad e interfaces humanas: el tiempo de respuesta que percibe el usuario.
De Menéame nos podrán criticar todo, salvo que sea lento o que no hayamos tenido en cuenta este aspecto tan importante, por eso cuento unas pocas reglas que hemos seguido muy estrictamente. Algunas las conocíamos, otras hemos aprendido durante estos casi cinco años de desarrollo.
Hay muchos parámetros a tener en cuenta para desarrollar sitios web que sean «rápidos». No sólo hay que tener en cuenta la velocidad de los servidores, o el tiempo que el servidor en generar un HTML dinámico, hay muchos otros parámetros que afectan directamente al navegador y la percepción de los usuarios.
En julio de 2001 escribí un artículo en Bulma donde expliqué, basado en la experiencia y mediciones durante el desarrollo de los primeros sitios de Diari de Balears y Última Hora (en los años 1997-1998), los parámetros o mediciones técnicas fundamentales a tener en cuenta: tiempo de respuesta, tiempo de retorno, tiempo de descarga y el «tiempo para la visualización». Este último parámetro, el de visualización, es el que más efecto tiene para el usuario. Éste espera una respuesta rápida, esa «respuesta» se suele percibir por el tiempo que tarda en empezar mostrarse la página en el navegador.
En el artículo comento con ejemplos como se puede hacer que el tiempo de visualización sea mucho menor que el tiempo total necesario para generar y descargar el HTML completo mediante una maquetación optimizada. Así, una página maquetada sin tener en cuenta estos parámetros toma, de acuerdo con las mediciones de esos años, seis segundos para ser visualizadas.
Tvis = Tdescarga = 0.5 seg + 40 KB/7.5KBseg = 0.5 seg + 5.33 seg =~ 6 segundos
En cambio la misma página, pero formateada adecuadamente puede reducir el tiempo de visualización a un segundo.
Tvis = 0.5 seg + 4 KB/7.5KBseg = 0.5 seg + 0.53 seg =~ 1 segundo
Esas mediciones se hicieron cuando reinaban las tablas, casi no se usaba CSS ni Javascript. Aún así las cosas han empeorado, incluso con el espectacular aumento de ancho de banda (lo mejor que había en 2001 era el RDSI a 64 kbps y muy pocas conexiones de 128 o 256 kbps), navegadores y potencia de cálculo hay muchos sitios populares que tardan más de seis segundos en visualizar la página.
Los problemas siguen siendo los mismos, aunque más complejos por esa influencia de los CSS, Javascripts, publicidad, librerías, efectos etc. Sería largo de explicar todas las recetas, pero aquí van algunas de las reglas que seguimos estrictamente en Menéame:
1. Minimizar las inclusión de CSS y Javascript
Los CSS y la mayoría de ficheros de Javascript se indican al principio del HTML y son bloqueantes, i.e. hacen que el navegador detenga todo el proceso de «dibujado» hasta que se hayan bajados todos los ficheros. Piensa mucho bien antes de incluir alegremente tantos ficheros CSS y Javascript en tu página, especialmente estos últimos. No es gratuito, todo lo contrario, estarás molestando mucho a tus lectores o usuarios. La regla fundamental es: minimiza el número de CSS y Javascript, no incluyas librerías que no necesitarás, minimiza el número de imágenes dentro del CSS (que generan conexiones adicionales).
Es muy común que blogs y sitios webs incluyan todo tipo de javascript externo (los widgets) sin tener en cuenta la penalización temporal que ejercen sobre su página. Estos javascripts bloquean completamente y se suele notar, especialmente si no fueron desarrollados cuidadosamente para evitar que el bloqueo sea prologando. Los buenos scripts suelen ser un pequeño código que sólo define un iframe de tamaño fijo y hace que éste cargue a posteriori el resto de javascript (con las consultas necesarias). Un ejemplo de buenos scripts en este sentido son los de Google AdSense.
Así que si no tienes más remedio que incluir javascript externo fíjate cómo está desarrollado, descarta aquellos que bloquean el dibujado de la página mientras hacen sus consultas a servidores externos. Si no te queda más remedio que utilizar esos script bloqueantes y lentos, tómate el trabajo para evitar el problema. Es lo que hicimos en el Menéame en los dos bloques de publicidad que se ven.
La publicidad se genera a partir de ficheros javascript del servidor de Social Media S.L. Este servidor verifica primero si hay alguna publicidad contratada para nuestro sitio de sus propias bases de datos y de bases de datos de terceros. Si no es así redirecciona para que se carguen los anuncios de AdSense. Todo este proceso es bastante lento y el API del servidor no está optimizado. La solución que usamos y se puede aplicar para cualquier sitio con un problema similar:
No se carga directamente al Javascript, sino que definimos un iframe de tamaño fijo y un html independiente que se carga de nuestros servidores. El html de ese iframe es el que incluye los javascript de publicidad. La carga del contenido del iframe no bloquea la página y tiene menos prioridad. Esta es la razón de que si váis al Menéame la publicidad se suele muestra después que se haya dibujado la página completa (probadlo y veréis el efecto).
Ya sabéis el truco que hay que hacer para solucionar esos widgets lentos, tómate el trabajo, tus lectores te lo agradecerán. Pero aún más importante: si eres desarrollador de widgets o plugins haz lo mismo en tu scripts. Aquí tienes un ejemplo de cómo lo hacemos para el «contador de votos» de Menéame check_url.js o este otro similar pero más elaborado.
Nota: está el atributo defer de la etiqueta script, pero usadlo con cuidado, tuve muchos problemas cuando lo intenté usar.
2. Retrasar la carga de Javascript que no sea necesaria para mostrar la página
Como comentaba en el punto anterior, hay que intentar minimizar el número de ficheros javascript que se incluyen al principio de la página. Cuando hay que cargar ficheros adicionales lo mejor es ponerlos al final del html, justo antes de la etiqueta </body>.
A veces no es simple porque esos javascript se pueden necesitar para mostrar contenido en la misma página. Eso se puede solucionar, como hacemos en el caso de noticias que tienen geolocalización y el mapa de Google Maps se muestra en la barra lateral, por ejemplo en esta noticia. La intención es retrasar lo máximo posible la carga del Javascript adicional de Menéame y el de Google Maps.
Podéis ver que el código que lo hace está al final del html, justo antes del </body> (el primer script incluye el API de Google, el segundo las funciones propias de Menéame):
<script type="text/javascript" src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAocztgtKfY7lNdoKmmVwCrRTm04PVUmrAy_OEGIhbf1bFTbg4wRQr-dfRhZoi0UaKDoqFRXUZXOgLuw"> </script> <script type="text/javascript" src="http://aws.mnmstatic.net/js/geo.js"> </script>
Al principio del HTML insertamos una llamada a geo_coder_load (definida en geo.js que se cargará al final) pero que se llamará después que se haya cargado todo el contenido usando la función $.() de Jquery:
<script type="text/javascript"> $(function(){geo_coder_load(34.0104402,-118.4983353, 5, 'published');}) </script>
En el lugar donde queremos que se inserte el mapa sólo definimos un div con las medidas deseadas:
<div id="map" style="width:300px;height:200px;margin-bottom:25px;"> </div>
Lo que pasará es que la página se cargará y dibujará completamente, sólo entonces se llamará a la función geo_coder_load que llamará a las funciones del API de Google Maps para que dibuje el map en el div con id «map». Así evitamos que se bloquee la página mientras se carga el «inmenso» mapas (por eso, al igual que la publicidad, el mapa se muestra con «retraso»).
3. Maquetar de forma que se pueda «dibujar» parte de la página aunque no se haya bajado todo el HTML
En el artículo de Bulma de hace casi diez años comentaba el mismo tema, aunque orientado más a tablas los principios son los mismos:
- Separar en módulos que puedan ser dibujados inmediatamente, por ejemplo la cabecera.
- Definir todas las dimensiones de imágenes, áreas (por ejemplo el alto de la cabecera, el ancho de las columnas, etc.) y espacios:
En Menéame el ancho de completo ya se define en el CSS:
#wrap { min-width: 952px; max-width: 1200px; margin: 0 auto; ... } #header{ height: 36px; ... } #naviwrap li{ width: 120px; height: 20px; .. } #sidebar { float: right; width: 300px; ... }
En cuanto el navegador interpreta el CSS de esas tres divs ya puede calcular las dimensiones necesarias para poder dibujar rápidamente: el ancho que tendrá la parte visible, el alto de la cabecera superior, el alto del menú de la izquierda y el ancho de la columna de la derecha (y por lo tanto ya calcula el ancho de la columna principal de contenido).
La parte que toma más tiempo de CPU en la portada o una noticia de Menéame es la consulta a los enlaces o los comentarios. Para disminuir aún más el tiempo de visualización lo primero que se envía al navegador es el contenido de la columna derecha (el #sidebar), como el ancho ya está especificado puede mostrarla aunque no se haya recibido el HTML de la columna principal. Por eso en conexiones u ordenadores lentos veréis que se empieza dibujando por la columna de la derecha.
4. Utilizar dominios diferentes para el contenido estático
Los navegadores (o al menos la mayoría) paralelizan las descargas de sitios diferentes al original, por eso es mejor que dichos ficheros se bajen de un dominio diferente.
<link rel="stylesheet" type="text/css" media="all" href="http://aws.mnmstatic.net/css/es/mnm65.css"/> ... <link rel="shortcut icon" href="http://aws.mnmstatic.net/img/favicons/favicon4.ico" type="image/x-icon"/> ... <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js" type="text/javascript"></script> ... <meta name="thumbnail_url" content="http://aws.mnmstatic.net/img/mnm/eli_thumbnail.png"/> ... <img src="http://aws.mnmstatic.net/img/common/search-left-04.png" width="6" height="22" alt=""/> ... <img src="http://aws.mnmstatic.net/cache/00/01/1-1280021590-20.jpg" width="20" height="20" alt="gallir"/>
La línea 3 es interesante. Hay librerías, como las JQuery, que son usadas por muchísimos sitios. Aunque se trata siempre del mismo código cada sitio incluye su propio fichero, lo que obliga al navegador a bajar una y otra vez lo mismo. Para evitarlo Google puso a disposición el servidor Google Apis, donde mantiene una copia de esas librerías para que puedan ser usadas por cualquier sitio. Si todos los sitios importantes los usasen se ahorraría mucho tiempo de los usuarios (además los servidores de Google suelen estar distribuidos y se bajan de sitios con la menor demora).
5. Usar dominios diferentes, no subdominios, para contenido estático
Esta apartado podría ser un subapartado del anterior, incluso el mismo, pero lo puse por separado ya que es un truco muy bueno para sitios complejos (con uso de cookies) y muchas imágenes o ficheros estáticos.
En el ejemplo anterior se puede ver que no usamos un subdominio de meneame.net (por ejemplo static.meneame.net) para servir el contenido estático, sino uno completamente diferente. El objetivo evitar agregar tráfico adicional por los cookies que se usan.
Cada cookie que se define en un dominio implica que por cada conexión el navegador envíe al servidor el valor de esos cookies. Esto pasa incluso para bajarse unas imágenes pequeñas de pocos bytes. Además el ancho de banda de subida suele ser bastante inferior al de bajada. La situación se agrava aún más con los cookies que definen las herramientas de estadísticas como Google Analytics.
La forma de evitar ese tráfico inútil para el contenido estático, lo mejor es usar un dominio completamente diferente. Cuando implementamos esto en Menéame hicimos las pruebas y ahorrábamos 14 KB de tráfico para un navegador con la cache vacía.
6. Definir tiempo de caducidad para el contenido estático
Para evitar que los navegadores se conecten cada vez para verificar si un fichero estático fue modificado es mejor definirles un tiempo de caducidad bastante elevado. De esta forma el navegador no volverá a verificar ese fichero hasta que haya pasado ese tiempo.
En menéame usamos 10 días, en el nginx:
location ~* \.(gif|jpg|png|js|css|html|ico)$ { expires 10d; ... }
Por ejemplo para una imagen generará las siguientes cabeceras HTTP:
Cache-Control: max-age=864000 Expires: Mon, 06 Sep 2010 16:12:01 GMT
7. Comprimir el contenido de texto
Si un sitio está razonablemente bien programado, lo que más tiempo consume es la transmisión del HTML por la red, por eso los navegadores aceptan la versión comprimida. Con la potencia actual de los procesadores es mejor comprirlos antes de enviarlos, los servidores pueden hacerlo automáticamente y on-the-fly si el navegador lo acepta.
Por ejemplo la configuración del nginx para Menéame para comprimir en gzip:
gzip on; gzip_comp_level 4; gzip_proxied any; gzip_min_length 512; gzip_disable "MSIE [1-6]\.(?!.*SV1)"; gzip_http_version 1.0; gzip_vary on; gzip_types text/css text/xml application/x-javascript application/atom+xml text/plain application/json application/xml+rss text/javascript;
Hay más reglas y trucos para minimizar los tiempos, por ejemplo poner todas las imágenes del CSS en una sola y tratarlas como «sprites» [*], pero si respetas la mayoría de estas 7 reglas la mejora de velocidad de tu sitio será muy notable.
[*] Particularmente no me gusta esta opción para sitios donde el diseño es dinámico con el Menéame. Cada vez que se agregan o modifican iconos obliga a generar una nueva imagen, que además debe ser compatible en sus coordenadas con la anterior, caso contrario hay que redefinirlas en todo el CSS. Es mucho tabajo de «administración» y sujeta a errores. Pero sí la veo como buena medida para los plugins o widgets que incluyen iconos y serán usados por muchos sitios (por lo que la «estabilidad» es mucho más prolongada). Más o menos lo mismo pienso sobre minimizar los javascripts.
¡No necesitas servidores más rápidos! debes intercalar
Esta sección es más friki-informática, y es la que en realidad me motivó a escribir este apunte. Pero por esas cosas de «completitud» quedó última y la más breve.
La tendencia actual de programación web es de usar plantillas cada vez más sofisticadas y complejas. Ejemplos típicos son la de generar todas las consultas a la base de datos y luego generar los resultados HTML en un bucle FOR dentro de la plantilla. Ejemplos más sofisticados son la de incluir plantillas dentro de otras o usar las características de herencia (o bloques). Algo similar ocurre con casos más sencillos, como usar el output buffer del PHP.
La mitología informática dice que así se mejora la negociación TCP/IP y se minimizan los paquetes enviados. Posiblemente sea verdad para sitios muy sencillos por con contenido tan simple que se genera muy rápido. Pero la realidad es que los sitios actuales generan páginas de varias decenas de KB (el HTML de la portada de Menéame tiene una media de unos 50-60 KB, una noticia con muchos comentarios puede llegar fácilmente a los 200 KB).
Hace pocas semanas liberamos Haanga, el sistema de plantillas de Menéame. Aunque éste permite la herencia no usamos esa características. Ni usamos el output buffer de PHP. Tampoco usamos los grandes bucles FOR, sino que el contenido se genera progresivamente para cada noticia, comentario o nota. Esta generación progresiva del HTML se usa para todos las partes de la página, para la cabecera, el pie, etc.
La razón es muy sencilla, así reducimos el tiempo de respuesta, el de retorno… y si se respetan las reglas comentadas anterioremente, el de visualización.
Un programa web tiene varias partes bien diferentes: consultas a la base de datos, lógica, generación de HTML, envío por la red. Para simplificar podemos considerar:
B: Consultas a base de datos y lógica:
H: Generación de HTML.
E: Envío a través de la red.
A: Ficheros adicionales (CSS, Javascript) que necesita bajar el navegador.
Así un patrón típico cuando se usa buffer del PHP, o se genera el HTML vía un template al final de la lógica sería (en azúl y sólo como referencia el momento en el que el navegador puede empezar a mostrar contenido):
BBBBBBBBBBHHHHHEEAAAEEEEEEEEEEEEEEEEEE
En la figura tenemos:
- diez «unidades de tiempo» (llamémosles «tics») para la lógica y consultas a la base de datos,
- cinco tics para la generación del HTML,
- veinte tics para la compresión (si está habilitada) y descarga por la red y
- tres tics para descargar ficheros adicionales.
Por supuesto es sólo un dibujo aproximado, si se usan plantillas más complicadas la generación de HTML podría tomar más tiempo que la lógica y consulta de base de datos. O viceversa si el HTML es simple pero las consultas son complicadas.
En el ejemplo el tiempo total que toma para bajar todo el HTML es de 38 tics, con suerte el usuario podrá empezar a visualizar la página web a los 20 tics.
Si el web es muy lento, la mayoría de programadores decidirán que lo mejor es poner un servidor de base de datos o web que sea más rápido, o que permita disminuir la carga y por lo tanto se reducirían los tiempos de base de datos y generación de HTML. Pero no es tan fácil, sobre todo porque la conexión al servidor de base de datos involucra –al menos para sitios grandes– conexiones vía red. Aunque se aumente la velocidad del procesador, el tiempo de latencia de la red sigue siendo el mismo.
Aún así, supongamos que cambia por servidores y redes más potentes y logra reducir casi a la mitad [*] el tiempo de base de datos y generación de HTML:
BBBBBHHHEEAAAEEEEEEEEEEEEEEEEEE
Después de la inversión para conseguir semejante mejor y el trabajo de migrar a una nueva infraestructura habrá reducido el tiempo total a 31 tics (18 % de mejora) y el tiempo de visualización a 13 tics (35% de mejora).
[*] Habitualmente la programación web es de un sólo «hilo», por lo que poner más procesadores o con más núcleos no acelera una ejecución. La única solución es aumentar los MHz, pero doblar los MHz tampoco implica que se reduzca el tiempo a la mitad (ni mucho menos) por lo que el coste para lograrlo suele ser muy elevado.
Pero este programador se olvidó de algo importante que aprendió en sus estudios y que es fundamental es informática, sistemas operativos y multiprogramación en general: la intercalación.
Si no la hubiese tenido en cuenta se habría dado cuenta que lo que tocaba era «adelantar» la generación del HTML para hacerlo progresivo y empezar la compresión y el envío mientras se hacen las demás consultas a la base de datos. Así el dibujo original, con los «servidores más lentos» le hubiese quedado algo como lo siguiente:
EEBBBBBBBBBBHHHHH
AAAEEEEEEEEEEEEEEEEEE
En se empieza a enviar inmediatamente el contenido que es inmediato o necesita muy pocas consultas (como la cabecera y la barra lateral del Méneame) para que el navegador pueda empezar a interpretarlo. Con estos números el tiempo total es de 23 tics (40% de mejora) y 5 tics para la visualización (75% de mejora). Los resultados son mucho más espectaculares sin cambiar nada de equipamiento, sólo «adelantando» la evaluación de los templates (y/o deshabilitando el output buffer).
Por supuesto esta «espectacular» mejora depende mucho de la aplicación. Menéame es un caso más o menos extremo en sus tiempos, la lógica y consultas a la base de datos están muy optimizadas y por lo tanto consumen muy poco tiempo relativo. Los siguientes son tiempos resultantes de 100 mediciones sobre los servidores en producción a una hora de mucho tráfico (hoy viernes entre las 12:00 a 12:30 hs)
- La lógica más base de datos (B): media 0.03348 seg (desviación estándar 0.02155)
- Lógica más base de datos (B) + generación HTML (H): 0.04663 seg (desviación estándar 0.02903)
- De #1 y #2 se obtiene que la media de H es: 0.01315 seg
Como daría mucho trabajo rehacer los programas y plantillas hice la prueba habilitando y deshabilitando el buffering y la compresión. La siguiente tabla muestra el tiempo total medio (en segundos, contando el establecimiento de una nueva conexión TCP/IP) que tarda en bajar el HTML de la portada (14 KB comprimidos, 57 KB sin comprimir, aproximadamente):
Sin compresión | Con compresión | |||
Sin buffer | Con buffer | Sin buffer | Con buffer | |
ONO 12 Mbps | 0.52 | 0.61 | 0.32 | 0.34 |
3G Vodafone | 1.09 | 1.12 | 0.86 | 0.89 |
Se puede observar que sin buffering es algo más rápido pero la diferencia es mínima. Sí se nota la diferencia con la compresión habilitada, se llega hasta el 38% de reducción del tiempo.
Conclusiones
No uses el buffering de salida si no estás seguro de lo que haces y/o has hecho mediciones de tiempo. En general irá mejor sin buffer, y consumirá menos recursos del servidor (fundamentalmente memoria RAM).
Si tu aplicación con plantillas es compleja y el tiempo de procesamiento y consultas a la base de datos es relativamente grande, serializa, no generes todo a partir de un sólo template que llamas al final. Además ahorrarás memoria RAM y ciclos de CPU. En caso que no puedas serializar la generación de cada «objeto», al menos genera una plantilla independiente con la cabecera HTML y envíala lo antes posible, así el navegador podrá bajar en paralelo los CSS y javascripts.
Nota final sobre los dispositivos móviles e iPads
Ten en cuenta que muchos usuarios usan sus móviles o iPads para navegar, haz que sean más felices con sus cacharros cuando naveguen por tu sitio, que para eso se gastaron un pastón. Hay algunos trucos muy fáciles, como no mostrar contenido secundario, no cargar APIs «pesados», y usar el selector @media del CSS para ajustar tamaños, márgenes o no mostrar secciones completas.
Menéame tiene su sitio optimizado para móviles desde hace tiempo. Pocos lo conocían, así que hemos implementado la redirección automática al sitio de móviles si se detecta que el cliente es de móviles (teníamos más de 10.000 visitas diarias). Mucha gente se quejaba de esta redirección, así que la restringimos a que sólo se haga si se accede directamente a una noticia desde un sitio externo, o si se usa el enlace corto tipo http://m.menea.me/m5za (lo usamos por ejemplo en los envíos automáticos a Twitter).
Para aligerar la navegación por el sitio principal a esos usuarios hemos hecho varias cosas:
- No se genera el contenido de la barra lateral derecha (ni la publicidad superior).
- Se cambia el tamaño de la fuente, algunos márgenes y marca en el CSS como «oculta» (display: none) aprovechando el selector @media de los CSS:
/* Definitions for mobile, iPad and TVs */ @media print,tv,handheld,all and (max-device-width: 780px) { body { font-size: medium; } .sneaker { font-size: small; } #wrap { min-width: 320px; } #sidebar { display:none; } #singlewrap, #newswrap { margin: 5px 5px 0px 5px; } #footwrap { margin: 5em 5px 0 5px; clear: both; } .banner-top { width: 470px; } }
- No se muestran los mapas ni se carga el API de Google Maps.
- No se muestra el megabanner sino un anuncio de AdSense más pequeño.
Interesante, completo y consiso. No se puede pedir más, felicidades.
La version movil es genial, no entiendo como no esta mas pulida.
Muy interesante en cualquier caso el css usado en las visualizaciones desde dispositivos moviles.
@selvatgi
Porque fue diseñada en la época de los Nokia. Ya tenemos el diseño nuevo, a ver si en los días que vienen lo maquetamos (estábamos esperando acabar con la migración a Haanga, que ya está casi acabada).
Grandes lecciones Ricardo. Me encanta todo.
Lo he guardado para volver a leerlo mañana con más calma, en horario laboral jeje.
Sobre los sprites a mi me encantan. Y te recomiendo que uses esta «tecnologia».
No es tan engorroso como dices (por mi experiencia). Solo hay que organizar bien las imagenes de forma que haya espacio para añadir más o cambiar el tamaño. Y sobre todo, indicar las coordenadas y tamaños en el CSS de forma que aunque realmente sea un pequeño lio, al menos esté todo en el mismo sitio.
Lo llevo usando este año y creo que merece la pena usarlo. En menéame molaría que lo aplicases.
Las dos ventajas que veo, a parte del ahorro enorme de carga de archivos, es que la visualización del diseño se renderiza «de golpe» lo cual queda genial. La otra ventaja interesante es que permite hacer efecto rollover perfecto sin que suponga un coste apreciable.
Este es el ultimo sprite que uso en Teoriza: http://img.teoriza.com/bt/sprites3.png
En menéame sería un poco más grande claro. Pero imaginate, meter los iconos, etc… Yo no me lo pensaba.
Si quieres te ayudo, que me mola el tema (y a selvatgi también ;).
Un saludo!
Un articulo completo y exelente! Gracias
muy buen artículo …
lo de cargar los scripts externos que relentiza la carga de la página, lo he aplicado al contador de visitas y genial, ya que antes, hasta que no conseguía recuperar dicha consulta, me bloqueaba el resto de la página …
Gracias por este post tan clarificador.
Aunque algunas partes del mismo (sobretodo la parte friki-informática) se escapan a mi entendimiento, como diseñador me gusta saber cómo «se muestra» lo que maqueto, y lo has explicado de una manera muy clara y elocuente.
🙂
Saludos,
Muy buen artículo, gracias.
Gallir una duda que tengo sobre lo de las cookies:
Como sabes soy partidiario de no usar las «www.» (si entras con «www.» a sigt te redirige a la versión sin las «www.») pero eso hace lo que tu dices: envías cookies para pillar contenido de «static.sitio.com» ya que las cookies se rigen a nivel de dominio en lugar de subdominio («www.»).
Sin embargo si hubiera elegido usar las «www.» se puede usar cookies en «www.sitio.com» y no se envían a «static.sitio.com» (es la única ventaja real que le veo a usar las «www.»).
Supongo que no hay solución técnica (alguna opción/workaround) aparte de usar un 2º dominio ¿verdad?. ¿O me he saltado algo y hay más ventajas al 2º dominio aparte de no enviar la cookie?.
Por otro lado el «dibujado» de una página tiene mucha miga, supongo que estás al tanto pero el tema de los selectores eficientes en CSS lo encontré de lo más interesante: aceleras el procesado de la página en los navegadores aunque el tiempo de generación y recepción del contenido sea el mismo.
En cierto modo hemos pasado de usar tablas (y algunos de usar una meta-tabla que aumenta de forma absurda el tiempo «de carga» de la página) a usar cientos de líneas en CSS y varias de ellas poco eficientes…
Sobre la última parte referida al iPad, como usuario del mismo, echo de menos la barra de la derecha, o al menos podrías poner una pestaña «candidatas» para estos dispositivos. Además, si bien no me importa que no se vean los mapas, si debería permitir geolocalizar las noticias enviadas. Un saludo.
Muy interesante, algunas cosas ya las sabía gracias al proverbial «ensayo y error», pero siempre viene bien tenerlo todo resumido.
@armonth
La «ventaja» que dices del «www» es cierta, aunque no sé si los Analitycs aún así pueden poner al dominio de primer nivel.
Nota: nosotros usamos el www obligados por el LoadBalancer de Amazon, es un CNAME que no se puede usar en primer nivel.
Excelente,
especialmente para los que tenemos el servidor montado en el ordenador de casa y andamos algo paranoicos con la optimización/rendimiento.
En mi caso mediante javascript voy tratando de retrasar la carga de elementos más pesados, especialmente imagenes de Flickr y embed de Blip.tv y Youtube.
Concretamente los embeb de Blip.tv motivaron mi «interes» por esta optimización, los cabrones parecian un palo entre las ruedas cada vez que se cargaban…
Yo también pienso que la mayoría de las páginas están sobrecargadas y son lentas. En una conexión rápida no se nota demasiado y con paciencia se puede trabajar.
Estos días he estado de vacaciones en un pueblo Amazónico de unos 200.000 habitantes donde la conexión más rápida era de 33600 baudios.
El simple hecho de leer un periódico era una tarea ardua de minutos por página. Algunas páginas de chorradas directamente eran imposibles para mi paciencia.
Hablando allí con la compañía telefónica que provee el servicio internet, me comentaron que había unos 2500 abonados en el pueblo y una lista de espera de más de 1000 personas pero que no podían aceptar por falta de ancho de banda.
Allí las centralitas son analógicas y cualquier inversión es inviable.
Me temo que esa situación no es un caso aislado, y el que publica páginas debe pensar hasta que publico quiere llegar.
Buen articulo. Muchas gracias, nos ha dado ideas.
Buen articulo pero… ¿que me dices de la accesibilidad de meneame?. No pasa el nivel A de las WCAG, si cargará muy rápido y tal… pero se esta discriminando a mucha gente con alguna diversidad funcional.
@alpine
Según http://www.totalvalidator.com/ nos da A2 la mayoría de los errores son muy chorras, la mayoría por el javascript y algunos imposibles de arreglar manteniendo la validación xhtml. Hay algunos que incluso se quejan de CSS perfectamente válido, otros con » Different links that use the same link text may be confusing» pero no podemos cambiar los enlaces ni el texto (o no tendrían sentido).
En http://www.cynthiasays.com/ pasa perfectamente el Priority 1.
La mayoría da errores por el javascript, por ejemplo que no se ponga «», pero es que hay sitios donde no hay forma (y Menéame sin javascript no funciona).
OTH Es una locura validar, sobre todo si tienes mucho AJAX http://www.alistapart.com/articles/tohellwithwcag2
Pingback: Piensa un poco en los lectores de tu sitio web: optimiza lo fundamental, intercala y elimina
Muy buen articulo, espero reducir el tiempo de carga de mi sitio!!
saludos
Excelente!! con mas de uno de los puntos que analizas me los he cruzado y valla que fueron dolores de cabeza. Gracias por este resumen.-
Saludos
Pingback: BeOSmAn's Blooog | Optimizando sitios Web
Pingback: Sin tiempo para escribir.77
Ricardo me ha gustado y parecido muy útil el artículo. Tras leerlo he buscado alguna web que mida la velocidad de carga de las web para comprobar la velocidad de la mia. He puesto ha cargar un enlace de mi web, que ademas de mostrar el video de una cación, lee la api de youtube buscando canciones relacionadas, intenta detectar el grupo de musical de forma automática mediante llamada a Api de Last fm y tras ello si lo detecta te crea la sección información del grupo, su discografia y una radio con canciones parecidas. Es decir, realiza bastante funciones. Además reconozco que no he depurado nada mi código, siempre lo voy posponiendo…. Bueno al final resulta que la carga de mi web es en 1.8 segundos y en cambio menéame.net ha tardado 3.1 seg.
Los resultados :
Mi web : http://tools.pingdom.com/?url=http://www.fliis.com/%3Fv%3D98W9QuMq-2k&treeview=0&column=objectID&order=1&type=0&save=true
Meneame: http://tools.pingdom.com/?url=meneame.net&treeview=0&column=objectID&order=1&type=0&save=true
Mi pregunta es, crees que me merece la pena retocar y mejorar todo el código si ya se carga en 1,8 segundos?
Un saludo
Otra duda que me surje, el tema de incluir la publicidad de google en un iframe para que no retrase la carga, ¿ no quita eficacia a google para conseguir mostrar los anuncios relacionados con el contenido de meneame?
Saludos de nuevo
@javier
Sobre tus mediciones:
1. Te has equivocado de hostname (por lo que agregas redireccionamientos de IP diferente), es http://www.meneame.net, no meneame.net. Con http://www.meneame.net me sale 1.8 segundos en total.
2. Ese sitio prueba las conexiones desde EEUU, los servidores de Menéame están en Dublin (a posta). Por eso la mayor parte del tiempo se pierde en la parte «amarilla» que es «inicio de conexión.
3. Posiblemente no hace cache de DNS correctamente (hay un TTL muy corto por el loadbalancer) y eso es parte de las barras amarillas.
4. No usa compresión, ni empieza a bajar los javascript /CSS apenas los recibió, sino cuando acabó de bajar todo el HTML.
5. Fíjate que lo que mas tarda es el javascript desde los servidores de Google. Algún problema tiene.
Resumen: muy malo el benchhmark. Usa otras cosas, como el Google Speed para Firefox, o el «Timeline» del Developers Tools de Chrome (en el mío me da 1.74 segundos para bajar y mostrar todo, incluida la publicidad)
Ricardo si tienes un momento comentame lo que opinas de aplicar sprites a meneame (te comenté mi experiencia arriba).
Aplicarlo es cuestion de 1 hora (problemillas a parte). Pero merecerá la pena seguramente. Sería interesante ver el resultado en producción de una web con tanto trafico.
@gonzo
Ya lo expliqué en el apunte, que no lo hacemos por la sobrecarga de trabajo y coordinación. Cuando estabilicemos estos cambios de diseño y templates podría ser. Por ahora no es prioritario, nos llevaría más problemas y ya está bien compensado por la caducidad y sobre todo el soporte de keepalive que lo baja en una sola conexión TCP/IP.
PS: Tampoco tenemos demasiadas imágenes en el CSS, 26 exactamente, y son pequeñas.
@armonth @gallir Felicidades por el post, he aprendido varios trucos 😀
Sólo «discreparía» sobre el tema CSS Sprites, poniéndolos en vertical y en un mismo orden, por ejemplo ordenados por fecha, se puede hasta generar el Sprite dinámicamente y cachearlo, sin ajustar nada de nada en el CSS para añadir imágenes 😀
De lo de los dominios «cookieless» ya os confirmo yo que sí, yo definí en Analytics el cookie domain como www, el mismo que uso para la web, y utilizo media.dominio.com sin problema para estáticos, sin cookies 😀
Un post mio similar, aunque más orientado al browser que al servidor es http://www.propiedadprivada.com/twitterposter-on-steroids/281/ , donde se comentan entre otras las técnicas de CSS Sprites (Salvando las distancias… que es del año del canuto!)
Nada como pasarse por aquí para encontrar sentido a la frase «sólo sé que no sé nada» 🙂
Ricardo gracias por las explicaciones, tendré que hacer tiempo para aplicarme en esto de los tiempos de carga.
Tomo nota y gracias por las recomendaciones.
Saludos
Estupendo artículo Ricardo, muchas gracias.
Pero añadiría algunas cosas. Para optimizar la carga de una página hay que tener en cuenta 3 puntos.
1.-Reducir el tiempo de cada petición.
2.-Reducir el número de las peticiones.
3.-Optimizar la renderización (CSS, JavaScript) de tu página.
Creo que tu artículo trata sobre todo el primer tema.
Para reducir el número de peticiones HTTP, ademas del tema de la configuración de la cache, esta el tema de los CSS Sprites y si no te gusta otra alternativa es sustituir la referencia a la imagen por su representación en Base 64 dentro de la CSS. Aunque aquí nos encontramos con el problema del IE6/7. Ademas ya existen aplicaciones que dada una CSS te lo hacen automaticamente (cssembed).
http://jbravomontero.wordpress.com/2010/07/16/conversion-automatica-de-imagenes-a-data-uris/
http://jbravomontero.wordpress.com/2010/07/16/%C2%BFcomo-reducir-el-numero-de-peticiones-http-en-la-carga-de-una-pagina-web/
Y sobre el tercer punto, ademas de buscar la simplicidad en el código HTML, ademas de optimizar la ejecución del código Javascript, todavía falta mucho trabajo con la optimización de las CSS. Ya hay un comentario en el que explican por ejemplo el tema de como influye el rendimiento en el uso eficiente de los selectores CSS. Si no recuerdo mal es una de los temas que el Page Speed de Google te puede indicar.
Un saludo y gracias por el artículo.
Comentar, dentro del tema de los CSS Sprites, la posibilidad de crearlos diagonales, para evitar que unos iconos solapen a otros al crear elementos de altura no prevista. http://www.aaronbarker.net/2010/07/diagonal-sprites/
Eso si, hay que tener mucho cuidado con el coste, el «footprint» de memoria, que una cosa es tener 1000×1000 pixels comprimidos en un PNG, muy eficiente, y otra tener ese millón de pixels en ram en nuestro navegador, posicionando una y otra vez. http://urlcorta.es/2rz9
Pingback: Zona Bloguismo XLI | Bloguismo
Buenas Ricardo,
muy interesante el post (y porque no decirlo, todo el blog). Gran artículo, sí señor!
Y después del peloteo quería hacerte un par de preguntas desde mi ignorancia 😉 jeje
Cuando comentas el asunto de la intercalación y de evitar el output buffer de PHP, no podría también servirnos para ello hacer un flush del buffer con ob_flush? Por ejemplo, una vez q se tenga la cabecera llamar a esta función
No ganaríamos lo mejor de ambos mundos? (la intercalación y supuestamente leí q el uso del buffer era más eficiente. En mi caso lo utilizo con compresión ob_start(«ob_gzhandler») )
Y estaba echando un vistazo al archivo check_url.js.php… para q lo utilzas exactamente? puede q sea la dirección q das a páginas externas, para q añadan un botón para votar la noticia o añadirla a meneame?
He visto que en el php también añades el cache-control… yo en los js.php que utilizo no pongo el javascript en sí, sino que hago un include del archivo gzipeado (js.gz) y así no tengo q comprimirlo al vuelo. Supongo q en tu caso sería una chorrada por lo poco que pesa y porque ya te lo hace el nginx al vuelo, no?
Un saludo!