Cómo optimizar el tiempo de carga de tu página web

Juan Pedro Catalá

Escrito por Juan Pedro Catalá

En mi anterior artículo, analicé cómo afecta la velocidad de carga de tu página web al SEO, diferentes herramientas de medición y los diversos factores que influyen en el tiempo de respuesta. En este artículo platearé las mejoras que se pueden realizar en cada uno de los pasos de una solicitud a tu web para disminuir el tiempo de carga de la misma.

Como ya comenté en mi anterior artículo, un navegador realiza una serie de pasos para mostrar una página web cuando se introduce una URL en el navegador. A continuación, detallo un ejemplo de un usuario que quiere acceder nuestra página www.humanlevel.com.

Resolución de la IP dado el dominio

El primero de ellos es saber la dirección IP del servidor que aloja la página web de www.humanlevel.com para poder conectarse a él y descargarse la página. Para ello, el navegador lanzará una petición al DNS que tenga configurado el usuario en su conexión a Internet y le devolverá la IP del servidor donde esté la web de www.humanlevel.com.

Esta petición solo se realiza la primera vez que se accede a un dominio, ya que posteriormente se cachea en el navegador, el sistema operativo y el router durante un periodo, por lo que el tiempo de esta petición en las siguientes solicitudes al mismo dominio será despreciable ya que se obtendrá la IP de las cachés. Desgraciadamente como este es un proceso ajeno a nuestro servidor no podemos optimizar nada en este paso.

esquema de una petición DNS para obtener el dominio de una página web

Conexión del navegador con nuestro servidor web

Una vez el navegador sabe la IP de nuestro servidor procederá a conectarse al mismo para solicitarle la página que el usuario ha introducido en el navegador. Éste es el primer paso en el que podemos mejorar algo, ya que cuanto más cercano esté el servidor en el que está alojada nuestra web del usuario que quiere verla, menos tiempo tardará el navegador en conectarse a nuestro servidor.

Por lo tanto, si nuestro público objetivo y la mayoría de nuestro tráfico proviene de un país concreto lo más lógico sería tener nuestra web alojada en ese país, incluso si tenemos mucho tráfico centralizado de una región dentro de un país lo mejor sería encontrar un proveedor de hosting cuyos servidores estén en esa región.

Una de las cosas que tendremos que habilitar en nuestro servidor es que admita las conexiones persistentes conocidas como «Keep-Alive». Esto permitirá al navegador reutilizar la conexión inicial con nuestro servidor y realizar múltiples peticiones de recursos (hojas de estilo CSS, imágenes, JavaScript, …) reutilizando la conexión existente y evitando perder tiempo y recursos en conectarse de nuevo al servidor.

esquema de peticiones de una página web

Podemos ver si nuestro servidor tiene activo «Keep-Alive» analizando las cabeceras HTTP del servidor desde las herramientas para desarrolladores de Chrome (F12) si nos responde con la cabecera Connection: Keep-Alive.

Cabeceras de respuesta: una parte importante en la optimizacion de carga de una página web

Procesamiento de la página en el servidor

Ahora que el navegador del visitante ya se ha conectado al servidor donde está alojada nuestra página web, éste tiene que procesarla para generar el HTML que enviará al navegador. Para ello, lo más común es realizar una serie de consultas a una base de datos para obtener la información a mostrar. Cuanto menor sea el número de consultas a la base de datos y menos tarden en ejecutarse, más rápido enviará el servidor el HTML al navegador.

Una forma de hacer menos consultas a la base de datos es cachear los resultados durante un periodo de tiempo o hasta que el valor de lo guardado en la caché cambie en la base de datos. Otra forma de disminuir el tiempo de respuesta, es agrupar varias consultas en una única petición a la base de datos, de esta forma nos ahorramos el tiempo perdido por la latencia entre el servidor web y el servidor de base de datos.

Dependiendo de la programación de la página el servidor irá enviando el HTML al navegador según vaya pintándola o se esperará hasta que el HTML de la página esté completado para enviarlo al navegador. Lo ideal en este caso, sería que se envíe el principio del HTML hasta el cierre de la etiqueta <head> lo más pronto posible, ya que así el navegador empezará a descargar los archivos CSS y JavaScript que se encuentren en la cabecera mientras se termina de generar el resto de la página en el servidor.

Recepción y procesamiento de la página en el navegador

El navegador va leyendo el HTML de la página según le va llegando del servidor y va solicitando los recursos externos de la misma (CSS, JS, imágenes, …) conforme los va encontrando hasta un límite, ya que los navegadores tienen número máximo de descargas que se pueden realizar a la vez desde un mismo dominio. Esté número varía según el navegador (Internet Explorer, Firefox, Chrome, …) y su versión y va desde 2 hasta 10 o más si el usuario ha modificado la configuración del navegador cosa poco común.

Para aumentar el número de descargas simultaneas lo que se puede hacer es crear dominios estáticos espejo del principal para servir los recursos externos de la página, de esta forma, si por ejemplo estamos en Internet Explorer 8 que sólo permite 6 peticiones simultaneas y servimos la web desde www.humanlevel.com y los contenidos estáticos desde s1.humanlevel.com y s2.humanlevel.com podemos llegar a tener hasta 18 descargas en paralelo con la consiguiente mejora en la carga de la página.

Para ganar velocidad al servir los contenidos estáticos, lo mejor es incluir dentro de la sección <head> de la página la preresolución de los dominios estáticos, esto realizará la consulta al DNS de forma asíncrona mientras se sigue procesando el resto de la página. Para ello añadiríamos el siguiente código:

<link rel="dns-prefetch" href="//s1.humanlevel.com" />
<link rel="dns-prefetch" href="//s2.humanlevel.com" />

El servir los contenidos estáticos desde otros dominios también nos permite eliminar las cookies que usamos en programación, ya que éstas sólo deberían estar asignadas al dominio principal en este ejemplo www.humanlevel.com. Se debe tener cuidado cuando se realizan dominios estáticos espejo del principal, ya que se debe dejar pasar a éstos solo las peticiones de contenidos estáticos o realizar las redirecciones pertinentes para evitar que se indexe la web en el dominio estático. Debido a que resolver la IP del servidor de los dominios estáticos tiene un coste temporal como he comentado en el primer paso, no recomiendo tener más de dos o tres dominios estáticos, al no ser que sea para repartir la carga en una web con un tráfico enorme (en cuyo caso sería mejor opción utilizar un CDN) o con mucho contenido gráfico.

Otra opción que tendría que estar activada en nuestro servidor web de forma obligatoria es la compresión GZIP en todos los ficheros de texto (HTML, CSS, JS, XML, …), ya que disminuirá el tiempo de descarga de forma drástica. Para saber si vuestra página tiene activado el GZIP mirar si existe en la respuesta la cabecera «Content-Encoding» con el valor «gzip».

Una cosa a tener muy en cuenta es dónde se sitúan los tags <script>, para cargar el JavaScript, y los tags <link>, para cargar el CSS, en el HTML. Los tags <link> deberían ir dentro de la etiqueta <head> tan pronto como sea posible y los tags <script> justo antes de cerrar la etiqueta <body>. El HTML resultante sería similar a este:

<!DOCTYPE html>
<html lang="es">
   <head>
      <meta charset="utf-8" />
      <link rel="dns-prefetch" href="//s1.humanlevel.com" />
      <meta name="viewport" content="width=device-width" />
      <link rel="stylesheet" href="estilo.css" />
      <title>Mi titulo</title>
      ... resto de metas e información ...
   </head>
   <body>
      ... contenido de mi página ...
      <script src="script.js" async></script>
   </body>
</html>

Como se ve en el ejemplo, lo ideal en una página es que únicamente se descargue una hoja de estilo CSS y un archivo JavaScript, ya que así nos ahorramos conexiones con el servidor.

Es muy importante situar los tag <script> al final del <body>, ya que en el momento en el que el navegador encuentra un tag de <script> deja de procesar la página y bloquea las descargas del resto de recursos externos, por lo que por muchas descargas simultáneas que hallamos conseguido, si no situamos los tag <script> correctamente no nos servirán de nada.

Este problema del bloqueo de las descargas se soluciona con el nuevo atributo «async» que se ha añadido a los tag <script> en HTML5, ya que con este atributo le decimos al navegador que procese el JavaScript de forma asíncrona sin bloquear el renderizado de la página. El problema es que los navegadores antiguos (Internet Explorer <= 8 y versiones antiguas de Firefox) no lo soportan.

Pese a la mejora que representa el atributo async, debemos de tener cuidado a la hora de cargar demasiados scripts (sobretodo los externos como los de las redes sociales) en las páginas, ya que estos scripts pese a ser asíncronos cargan un iframe con scripts que no son asíncronos bloqueando así las descargas de nuestra página. Para solucionar este problema lo mejor es cargar todos los scripts externos una vez se halla cargado nuestra página completamente, para ello se puede utilizar el evento window.onload de JavaScript.

Una vez hemos conseguido optimizar al máximo las descargas de recursos externos de la página y ya los hemos descargado, lo mejor que podemos hacer es evitar volver a descargarlos en otra página que también los utilice. Para ello, debemos configurar en nuestro servidor web que añada la cabecera «Cache-control: public, max-age=31536000» a los recursos estáticos. Esta cabecera, permitirá al navegador guardar en la caché todos los archivos estáticos durante un año, evitando así tener que volver a descargar de nuevo todos los archivos cuando vuelva a nuestra web.

Para concluir

En este artículo he repasado de forma general el proceso que realiza un navegador para cargar una página web y las mejoras que podemos hacer para agilizar la velocidad de la misma en cada uno de los pasos. Si aplicáis todas ellas podréis apreciar una mejora sustancial del tiempo de carga de vuestra web.

  •  | 
  • Publicado el
Juan Pedro Catalá
Juan Pedro Catalá
Fue desarrollador web senior en Human Level. Graduado en Ingeniería Técnica en Informática de Gestión. Posteriormente realizó un Máster en Desarrollo de Aplicaciones y Servicios Web. Especialista en desarrollo web, e-commerce y motores de reserva.

5 comentarios

¿Y tú qué opinas? Deja un comentario

Por si acaso, tu email no se mostrará ;)

  1. Muy buenos consejos, mi web está vinculada a un proyecto de laptops de primaria, las computadoras tienen Firefox 4.0 por medida de seguridad, lo malo es que el atributo «async» sólo funciona en versiones de Firefox 13.0.1 u posteriores.

  2. Gran post, completo y muy útil.
    Una pequeña duda: ¿qué hacemos con el código de Google Analytics? La documentación recomienda insertarlo en las cabeceras, pero para WPO se recomienda poner los códigos JS antes del cierre de
    Gracias!

    1. Hola Roberto, me alegro de que el artículo te haya resultado útil.

      Sobre el código de Google Analytics, yo soy partidario de incrustarlo dentro del fichero de JavaScript que se pone antes del cierre de body, así evitamos que el navegador se ponga a «parsear» el JavaScript de Analytics en cada página de nuestra web y detenga las descargas de otros recursos cargando la página completa más rápidamente.

      El único caso que se me ocurre en que puede que no se registrará alguna visita es que la persona le diera al botón de atrás, cerrará el navegador o se fuera a otra página antes de que se ejecute el código de Analytics, pero estas visitas lo único que harían sería aumentar el porcentaje de rebote sin ningún sentido, lo mismo ocurre cuando el código esté en el head.

      Un saludo.

      1. El código de google carga de manera asincrónica, entiendo que no debería ser un problema para la carga / performance de nuestro sitio.

      2. Hola Pablo,

        el código de analytics se carga de manera asíncrona, pero para añadir la carga asíncrona de google analytics se mete un < script > en la página que no es asíncrono que es lo que interrumpe las descargas.

        Un saludo.

Entradas relacionadas

es