Reducir el tiempo de respuesta de una página web con flush()
Empezamos esta serie de entradas con la función flush() porque es un método sencillo de implementar, porque tiene un gran rendimiento y porque rara vez se usa o se habla de él. En años y años de escribir código, y por lo tanto de estudiar el código escrito por otras personas (scripts, temas para WordPress, etc.), en raras ocasiones he visto usar esta función, y no alcanzo a comprender por qué. Yo siempre la he utilizado en las webs que he desarrollado, con excelentes resultados.
Flush() es una función de PHP que vacía el buffer de salida y trata de enviar todos los datos «escritos» (echo, print, etc.) hasta ese momento al navegador del cliente. Normalmente un script PHP se ejecuta en su conjunto y sólo al final devuelve los datos (código HTML, XML...) al cliente. Flush() evita esto permitiendo la ejecución del script «por partes».
¿En qué te puede ayudar esto?. Muy sencillo. Colocando llamadas a esta función justo antes de bloques cuya ejecución no sea «instantánea» (consultas a bases de datos, conexiones HTTP externas, etc.) conseguirás que tus visitantes empiecen a cargar las páginas antes, reduciendo el tiempo de respuesta e incrementando la velocidad de carga aparente.
Implementación
El uso de esta función es muy sencillo y está al alcance de cualquiera. Tan sólo hay que hacer una llamada a flush() dentro de las etiquetas de PHP y listo. Como puedes observar, no hace falta ser un experto para escribir el código:
- <?php
- flush();
- ?>
Si quieres ver a flush() en acción, y comprender de una forma más gráfica cómo funciona, puedes hacer la prueba de incluir éste código hacia la mitad de una página PHP (cuando ya se haya devuelto código que se pueda ver a través del navegador):
- <?php
- flush();
- sleep(5);
- ?>
Esto hará que se devuelvan todos los datos almacenados hasta ese momento para que después la función sleep() haga detenerse al script durante 5 segundos, por lo que verás exactamente en qué momento se ejecuta esa parte del código. Después de ese tiempo el resto de la página se cargará normalmente. Sin la llamada a flush() (prueba a eliminar esa linea) la página comenzaría a cargarse después de esos segundos (más el tiempo de ejecución normal del script). La llamada a sleep sólo sirve como ejemplo, no se te ocurra incluirla definitivamente en tu página.
Flush() en WordPress
Para la aplicación práctica vamos a tomar WordPress como ejemplo. Este gestor de contenido usa muchas funciones que ejecutan consultas a la base de datos en la que se almacena la información de las entradas, comentarios, categorías, etc. Dependiendo de cómo estén formadas, la calidad de tu servidor, la carga que esté soportando en ese momento, etc. cada una de esas consultas puede tardar un tiempo sustancial en ejecutarse.
Uses el tema (plantilla, o como quieras llamarlo) que uses, éste realiza consultas a la base de datos bien por sí mismo o bien mediante las funciones predefinidas de WordPress. Colocando una línea con flush() antes de que esas funciones sean llamadas evitarás que una consulta lenta retrase la carga de la página. Para que te hagas una idea, y siempre dependiendo del servidor, un tema puede llegar a tardar en ejecutarse desde unas pocas décimas a varios segundos. Sin embargo, antes de que se ejecute el código del tema, es decir, en el momento en que se dispone de los datos suficientes como para empezar a devolver código al cliente, se han llevado a cabo unas operaciones básicas de WordPress que tardan en efectuarse en torno a una décima de segundo (puede que más dependiendo de los plugins que tengas activos). Colocando un flush después del primer bloque de contenido estático del tema (encabezado, etc), la carga de la página empezaría justo en ese instante. Que una página empiece a responder en una décima de segundo en vez de en barios segundos evidentemente representa una notable mejora.
Para habilitar la carga por partes de un tema para WordPress, sólo tienes que editar los archivos .php de ese tema (que se encuentran en wp-content/themes/nombredeltema) y modificar el código justo antes de las llamadas a las funciones que realicen consultas a la base de datos. Típicamente en WordPress estas funciones son:
- wp_get_archives()
- wp_list_pages()
- wp_list_cats()
- wp_list_categories()
- wp_list_bookmarks()
- get_links_list
- get_links()
- wp_tag_cloud()
- get_posts()
- comments_template()
Por supuesto hay más, y de hecho algunas funciones pueden realizar consultas o no dependiendo de si los elementos a los que referencian están almacenados o no en la caché interna. Además, si el tema realiza consultas que no están contempladas en las funciones básicas de WordPress, muy probablemente use alguna de estas funciones de la clase $wpdb:
- $wpdb->query()
- $wpdb->get_var()
- $wpdb->get_row()
- $wpdb->get_col()
- $wpdb->get_results()
Para trabajar sobre un tema existente y que todo el mundo pueda consultar, vamos a implementar este método en el tema por defecto de WordPress (wp-content/themes/default). Primero podemos modificar el archivo sidebar.php de esta manera:
- ...
- <?php
- flush();
- wp_list_pages( 'title_li=<h2>Pages</h2>' );
- ?>
- <li><h2>Archives</h2>
- <ul>
- <?php
- flush();
- wp_get_archives( 'type=monthly' );
- ?>
- </ul>
- </li>
- <?php
- flush();
- wp_list_categories( 'show_count=1&title_li=<h2>Categories</h2>' );
- ?>
- <?php /* If this is the frontpage */ if ( is_home() || is_page() ) {
- flush();
- wp_list_bookmarks();
- ?>
- ...
Los cambios anteriores harán que la página empiece a cargar tras la primera llamada a flush() (justo después de que se hayan devuelto las entradas), y que esos bloques que pertenecen a la barra lateral del blog se devuelvan paulatinamente según se van finalizando las consultas (ésto no suele ser apreciable).
Sólo nos faltaría modificar de la misma forma los archivos single.php y attachment.php antes de la llamada a comments_template(), que es la que se encarga de extraer de la base de datos y mostrar los comentarios para cada entrada:
- <?php
- flush();
- comments_template();
- ?>
Por supuesto modificar cualquier otro tema para WordPress se hace de forma análoga (comprueba todos los archivos en busca de este tipo de funciones, no sólo los mencionados) y no debería suponer ningún problema. Haciendo algo de autobombo, 1 Blog Theme, el tema que usamos en la red 1Blogr (incluyendo este mismo blog) hace uso de flush() antes de cada consulta a la base de datos, por lo que tiene una carga muy liviana.
Cuándo flush() no funciona
En algunos casos flush() no cumplirá su labor, aunque de ningún modo devolverá un error. Por ejemplo, si tienes habilitada la compresión por Gzip en WordPress (Opciones > Lectura > WordPress debería comprimir las entradas (gzip) si los navegadores lo requieren), flush() no vaciará el buffer, ya que la salida se reserva para enviarla comprimida al final de la ejecución del script.
Flush() en otros lenguajes
Por supuesto la función flush(), o alguna análoga con los mismos resultados, estará disponible en la mayoría de lenguajes de programación de servidor. Por ejemplo en ASP (Active Server Pages) el equivalente es el método Response.Flush.
Esta entrada forma parte de la serie «Aumentar la velocidad de una página web en 7 pasos».
1 comentario
hace 2 meses y 14 días
Muy útil y sobre todo bien explicado.
Gracias
Escribir un comentario
Si quieres añadir tu comentario a esta entrada, simplemente rellena el siguiente formulario:
* Campos requeridos
Puedes usar estas etiquetas XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>.
3 trackbacks
Para notificar de una mención en tu blog a esta entrada, habilita la notificación automática (Opciones > Discusión en WordPress) o especifica esta url de trackback: http://1blogdeblogs.com/2007/08/reducir-el-tiempo-de-respuesta-de-una-pagina-web-con-flush.html/trackback