Optimizar código ASP clásico
Código ASP clásico
- Por Programador ASP clásico /
- 02/01/2012 @ 09:26:48 /
- 1254 visitas
El ASP es una tecnología dinámica funcionando del lado del servidor, lo que significa que cuando el usuario solicita un documento ASP, las instrucciones de programación dentro del script son ejecutadas para enviar al navegador únicamente el código HTML resultante. La ventaja principal de las tecnologías dependientes del servidor radica en la seguridad que tiene el programador sobre su código, ya que éste se encuentra únicamente en los archivos del servidor que al ser solicitado a través del web, es ejecutado, por lo que los usuario no tienen acceso más que a la página resultante en su navegador.
La demora entre el click de un usuario impaciente y el resultado devuelto en la pantalla de su navegador pueden hacer que el usuario se vaya del sitio.
No podemos tener control sobre la velocidad de la conexión del usuario, pero ciertamente podemos intentar optimizar nuestros sitios ASP para obtener el mejor rendimiento posible.
Recomendación: Utilice la extensión .asp en las páginas que al menos contengan una línea de contenido dinámico. Sino, serán páginas HTML convencionales y ahorrará muchos recursos simplemente cambiándoles la extensión a htm o html.
(1) Utilizar la directiva Option Explicit
Utilice la directiva Option Explicit en todas sus páginas ASP. Esta directiva debe colocarse al tope de las páginas ASP, pero debajo de la directiva @. Por ejemplo:
<% @ Language = VBScript %>
<%
Option Explicit
'otros códigos ASP
%>
La función de Option Explicit es forzar al programador a declarar todas las variables que utilizará. Por ejemplo:
<% @ Language = VBScript %>
<%
Option Explicit
Dim Variable_1, Variable_2
'otros códigos ASP
%>
Muchos desarrolladores consideran que esto es útil para la depuración de las aplicaciones, ya que evita la posibilidad de cometer un error de tipeo en el nombre de una variable e inadvertidamente crear nuevas variables (por ejemplo, Cadnea=... en lugar de Cadena=...).
Pero quizás lo más importante es que las variables declaradas son más rápidas que las no declaradas. El motor de ASP referencia las variables no declaradas por nombre, mientras que las variables declaradas tienen asignado un valor ordinal. De esta manera, las variables declaradas son referenciadas por este ordinal y así accedidas más rápidamente.
(2) Deshabilitar el estado de sesiones
Puede incrementar notablemente la velocidad de ejecución de sus aplicaciones deshabilitando el estado de sesiones desde la primera línea de toda página ASP que no utilice ningún objeto Session. Esto afecta sólo a la página en la que se indica explícitamente que no se van a utilizar sesiones y se logra colocando la siguiente declaración en la primera línea de la página ASP:
<% @ EnableSessionState = False %>
Esta línea debe ser la primera de la página ASP, sino recibirá un error similar a "El comando @ sólo puede usarse una vez en la página Active Server.".
Para efectuar más de una declaración @, como definir además el lenguaje del script, debería colocar todas las directivas en la misma línea (la primera línea de la página), así:
<% @ Language = VBScript EnableSessionState = False %>
La directiva EnableSessionState le indica al servidor que no inicie una nueva sesión cada vez que esta página ASP es llamada. Esto no quiere decir que no podrá mantener sesiones en las páginas que lo necesiten. En tales páginas no coloque esta declaración o indique explícitamente:
<% @ EnableSessionState = True %>
que es el valor tomado por defecto cuando no se utiliza la declaración EnableSessionState.
Otra de las razones para utilizar esta directiva es que las sesiones provocan un interesante problema con los marcos (frames). ASP garantiza que sólo un requerimiento de sesión será ejecutado en un determinado momento. Esto asegura que si un navegador requiere múltiples páginas a la vez para un mismo usuario, sólo un requerimiento ASP afectará la sesión a la vez, evitando problemas de multiprocesamiento al acceder al objeto Session.
Desafortunadamente, las páginas de un mismo conjunto de marcos (frameset) serán tratadas en forma serializada, una después de otra, en lugar de ser procesadas simultáneamente. Así, el usuario deberá esperar más tiempo debido a que cada página ASP de cada marco será procesada de a una. Como moraleja de la situación planteada, si ciertas páginas de un frameset no se ven afectadas por variables de sesión, asegúrese de indicarle esto a ASP a través de la declaración @EnableSessionState = False en tales páginas.
Nota: Si deshabilita el estado de sesiones y necesita asignar el "Locale ID" (LCID) para una página, puede hacerlo de la siguiente manera (el LCID indicado corresponde a Español-Argentina):
<% @ Language = VBScript EnableSessionState = False LCID = 11274 %>
(3) Habilitar Response.Buffer
Otra factor que mejorará el rendimiento de su aplicación web es asignar el valor true a la propiedad Response.Buffer. Esto acelera la ejecución debido a que no se envía ninguna respuesta al navegador cliente hasta que la página sea ejecutada completamente. Así, la respuesta es transferida de una sola vez en lugar de en pequeñas partes durante el proceso de ejecución.
Para habilitar el buffer en la respuesta de la página ASP debe agregar la línea Response.Buffer = True debajo de la directiva Option Explicit:
<% @ Language = VBSscript EnableSessionState = False %>
<%
Option Explicit
Response.Buffer = True
'otros códigos ASP
%>
TCP/IP funciona mucho más eficientemente cuando se envían unos pocos bloques de mayor tamaño en lugar de muchos bloques pequeños.
Una queja común al utilizar el buffer en la respuesta es que los usuarios perciben que las páginas ASP parecen más lentas (aún cuando el tiempo completo de procesamiento es mucho menor). Esto se debe a que los usuarios deben esperar a que la página entera sea generada antes de comenzar a ver algo.
Para páginas que requieren un considerable tiempo de procesamiento puede deshabilitar el buffer en la respuesta colocando Response.Buffer = False. Sin embargo, una mejor estrategia es utilizar el método Response.Flush. Este método envía al navegador todo el HTML que ha sido generado hasta un determinado momento. Por ejemplo, después de generar 100 líneas de una tabla de 1000 líneas, puede llamar a Response.Flush para forzar el envío de las 100 líneas al navegador. Esto permite que el usuario vea las primeras 100 líneas mientras se van procesando las 100 subsiguientes.
(notar que en el ejemplo anterior de una tabla de 1000 líneas, muchos navegadores no comenzarán a mostrar la tabla hasta que reciban la etiqueta de cierre </table>; para solucionar esto intente separar la tabla en múltiples tablas con menos filas y llame a Response.Flush después de que cada tabla ha sido generada completamente. De todos modos las últimas versiones de los navegadores comienzan a mostrar las tablas antes de que sean completamente descargadas, y lo hacen más rápidamente si especifica el ancho de las columnas de las tablas).
Otro reclamo común al habilitar el buffer en la respuesta es que este buffer puede utilizar una gran cantidad de memoria del servidor al generar páginas muy grandes. Más allá de la prudencia en no trabajar con páginas demasiado grandes, este problema puede ser corregido utilizando criteriosamente Response.Flush.
(4) Utilizar el objeto Session de forma prudente
Es recomendable evitar el uso de variables de sesión. Las sesiones producen múltiples problemas cuando son utilizadas en sitios web muy concurridos.
A menos que se explicite el no uso de sesiones a través de @EnableSessionState=False, ASP crea automáticamente una sesión por cada usuario que accesa una página ASP de una aplicación web. Cada sesión por sí sola toma unos 10 KB de memoria. La sesión permanece "viva" hasta que se cumple el período de TimeOut, que por defecto es de 20 minutos pero cuyo valor puede cambiarse a través de la siguiente directiva:
<% Session.TimeOut = xx %>
donde xx es un número entero que representa el período de TimeOut para la sesión en minutos.
Como una alternativa al uso del objeto Session, hay otras opciones para mantener el estado de las sesiones en una aplicación web. Usualmente se recomiendan cookies, variables QueryString pasadas a través de las URL's y variables ocultas (hidden) pasadas desde los formularios.
En el caso que no pueda evitar el uso del objeto Session, al menos asegúrese de NO colocar grandes cantidades de datos en este objeto. Colocar un objeto de ADO u otro objeto COM en un objeto Session será muy probablemente una causa de dolores de cabeza en el futuro cuando múltiples usuarios accedan la aplicación.
(5) Definir explícitamente las colecciones al utilizar el objeto Request
Para recuperar las variables enviadas desde formularios o a través de URL's, a veces utilizamos códigos como el siguiente:
<%
Dim Nombre
Nombre = Request("nombre")
%>
El objeto Request tiene cinco colecciones más una colección por defecto. Una llamada a la colección por defecto es la que se observa en el código anterior. Las otras colecciones son: Form, QueryString, ClientCertificates, ServerVariables y Cookies.
Todos estamos familiarizados con estas colecciones, ya que permiten ganar acceso a la información enviada desde el cliente.
Cuando se realiza una llamada a la colección Request por defecto, se busca en cada una de las subcolecciones en el siguiente orden:
QueryString
Form
Cookies
ClientCertificates
ServerVariables
El proceso se detiene cuando se encuentra la primera coincidencia. Si se está pasando una gran cantidad de información entre páginas, el uso de la colección por defecto puede resultar en retardos (especialmente si se está tratando de recuperar la colección ServerVariables).
Siempre que sea posible defina explícitamente la colección desde la que desea traer un valor. Por ejemplo, para el caso de una variable llamada "nombre" que proviene de un post realizado desde un formulario, la codificación correcta sería:
<%
Dim Nombre
Nombre = Request.Form("nombre")
%>
(6) Uso del archivo GLOBAL.ASA
GLOBAL.ASA es un archivo OPCIONAL que puede contener declaraciones de objetos, variables y métodos que pueden ser accedidos desde cualquier página de una aplicación ASP. Este archivo debe estar alojado en la carpeta raíz de la aplicación ASP y cada aplicación sólo puede tener un archivo GLOBAL.ASA.
Desde el GLOBAL.ASA puede indicarle a los objetos Application y Session qué hacer cuando la aplicación/sesión comienza y qué hacer cuando la aplicación/sesión termina.
Recomendaciones:
Si desconoce la funcionalidad de este archivo o no necesita utilizarlo, NO lo suba al sitio web. Cada usuario que acceda a una página ASP disparará los eventos definidos en el archivo GLOBAL.ASA.
No deje los métodos Session_OnStart o Session_OnEnd vacíos. Aunque no haya código en el cuerpo de estos métodos, igual son interpretados. El hecho que existan significa tiempo consumido tratando de invocarlos.
Por ejemplo, un archivo GLOBAL.ASA que no necesite hacer uso de los eventos Session_OnStart y Session_OnEnd debería verse similar a:
<Script Language="VBscript" runat="server">
Sub Application_OnStart
'código
End Sub
Sub Application_OnEnd
'código
End Sub
</Script>
Si desea ver la estructura completa de un archivo GLOBAL.ASA estándar y conocer más acerca de su funcionalidad, puede visitar el siguiente artículo: El archivo GLOBAL.ASA
(7) Evitar redimensionar las matrices
Trate de evitar redimensionar las matrices. En cuanto al rendimiento refiere, es mucho mejor asignar el tamaño inicial de una matriz al "peor de los casos" o a un tamaño considerado medio y redimensionar sólo en caso de ser necesario. Esto no significa que destine un par de megabytes de memoria a la matriz si sabe que no va a necesitarlos.
El código siguiente muestra el mal uso de Dim y ReDim:
<%
Dim Mi_Matriz()
Redim Mi_Matriz(2)
Mi_Matriz(0) = "Auto"
Mi_Matriz(1) = "Camión"
Mi_Matriz(2) = "Motocicleta"
'...
' otros códigos después de los cuales se da cuenta que necesita más
' espacio, entonces ...
Redim Preserve Mi_Matriz(4)
Mi_Matriz(3) = "Bicicleta"
Mi_Matriz(4) = "Triciclo"
%>
Es mucho mejor simplemente dimensionar la matriz al tamaño correcto inicialmente (en este caso a 4), que redimensionarla para hacerla más grande. Puede ocupar un poco más de memoria (si no termina utilizando todos los elementos), pero ganará en velocidad.
(8) Evitar la concatenación de cadenas dentro de bucles
Muchos programadores van construyendo una cadena de texto mientras recorren un bucle, como en el siguiente ejemplo:
Cadena = "<table>" & vbCrLf
For Each Campo in RS.Fields
Cadena = Cadena & "<th>" & Campo.Name & "</th> "
Next
While Not RS.EOF
Cadena = Cadena & vbCrLf & "<tr>"
For Each Campo in RS.Fields
Cadena = Cadena & "<td>" & Campo.Value & "</td> "
Next
Cadena = Cadena & "</tr>"
RS.MoveNext
WEnd
Cadena = Cadena & vbCrLf & "</table>"
Response.Write (Cadena)
Este código afecta seriamente el rendimiento de la aplicación. Concatenar una cadena repetidamente toma un tiempo de procesamiento cuadrático; el tiempo que toma ejecutar este bucle es proporcional al cuadrado del número de registros multiplicado por el número de campos.
Un ejemplo más simple quizás aclare la situación:
Cadena = ""
For i = Asc("A") to Asc("Z")
Cadena = Cadena & Chr(i)
Next
En la primera iteración se obtiene una cadena de un caracter (A). En la segunda iteración, VBScript tiene que redimensionar la cadena y copiar dos caracteres (AB). Y así sucesivamente...
En la iteración final N (26 para este ejemplo), VBScript tuvo que redimensionar y copiar N caracteres dentro de la variable "Cadena". Esto hace un total de 1+2+3+...+N que es lo mismo que N*(N+1)/2 copias.
En el ejemplo anterior del recordset, si había 100 registros de 5 campos cada uno, el bucle principal hubiese sido ejecutado 100*5 = 500 veces y el tiempo tomado para efectuar las copias y redimensionamientos sería proporcional a 500*500 = 250.000. Este es un número inmenso para un recordset de tamaño moderado.
En estos ejemplos el código podría ser mejorado reemplazando la concatenación de la cadena por Response.Write(), escribiendo directamente los datos en el cliente en lugar de almacenarlos en una cadena. Si Response.Buffer está asignado al valor "true" (como debería estarlo siempre), sería más rápido aún debido a que Response.Write() agregaría los datos al buffer del objeto Response.
Así, una manera mucho más eficiente de escribir el código del primer ejemplo sería:
Response.Write ("<table>" & vbCrLf)
For Each Campo in RS.Fields
Response.Write ("<th>" & Campo.Name & "</th> ")
Next
While Not RS.EOF
Response.Write (vbCrLf & "<tr>")
For Each Campo in RS.Fields
Response.Write( "<td>" & Campo.Value & "</td> ")
Next
Response.Write ("</tr>")
RS.MoveNext
WEnd
Response.Write (vbCrLf & "</table>")
(9) Comparar variables de un mismo tipo y utilizar variables locales
¡Compare manzanas con manzanas! En lugar de hacer que el motor ASP implícitamente busque los tipos de datos, fórcelo a que realice la comparación de la manera que usted necesita. Esto hará que las comparaciones ocurran de la manera que espera y se realicen más eficientemente.
Por ejemplo, en lugar de escribir:
If CLng(RS("lo_que_sea")) = 1 OR CLng(RS("lo_que_sea")) = 3 Then
almacene la variable localmente. Por un lado para evitar múltiples operaciones de conversión de tipos de datos y por otro para evitar leer el valor desde el recordset múltiples veces. Un código más eficiente sería:
lo_que_sea = CLng(RS("lo_que_sea"))
If lo_que_sea = 1 OR lo_que_sea = 3 Then
(10) Evitar el uso de Server.MapPath
El método MapPath del objeto Server mapea una ruta relativa o virtual a una ruta física en el disco del servidor.
No utilice Server.MapPath a menos que sea realmente necesario. Esto provoca otro requerimiento que el servidor debe procesar. Utilice los paths físicos directamente cuando desarrolle su sitio web para incrementar la performance. Si no conoce la ruta física a un archivo en el servidor de su proveedor de web hosting, ejecute el método Server.MapPath para saberlo. Por ejemplo, suba un script ASP en su sitio web con el siguiente código:
<% Response.Write (Server.MapPath("/")) %>
Al llamar este script desde un navegador podrá ver la ruta física de la carpeta raíz de su sitio web en el disco del servidor.
Medidor de Tiempo de Ejecución
A continuación se ofrece un script ASP que tiene la función de medir el tiempo (en milisegundos) que le toma a ASP procesar una determinada secuencia de código. Este script le será de utilidad para medir en su equipo de desarrollo cómo afectan al tiempo de ejecución los distintos consejos dados y otras prácticas de programación que desee ensayar.
Como generalmente las rutinas de prueba son sencillas (unas pocas líneas de código), usualmente devuelven tiempos tan pequeños que son mostrados como cero por el script de medición. Para obtener una mejor idea de cómo afecta una optimización en el código sobre el rendimiento, en algunas ocasiones es recomendable colocar el código a probar en un bucle para que se ejecute múltiples veces.
Por ejemplo, en el script suministrado se desea probar cuánto tiempo le toma al servidor crear y destruir un objeto recordset. Como el tiempo para realizar esta tarea para un solo recordset es muy prequeño, se realiza el mismo procceso de creacion/destrucción del objeto 10.000 veces. Entonces, el tiempo indicado por el Medidor de Tiempo de Ejecución corresponderá a la creación/destrucción de 10.000 recordsets (unos 200 milisegundos en una PC AMD Athlon XP funcionando a 2 GHz con 512 MB de RAM y con sistema operativo Windows XP / IIS 5.1).
Para utilizar el Medidor de Tiempo de Ejecución de scripts ASP con sus propios códigos de prueba, reemplace las líneas:
Dim RS, i
For i = 1 to 10000
Set RS = Server.CreateObject("ADODB.Recordset")
Set RS = Nothing
Next
por los códigos cuyo tiempo de ejecución desea medir.
IMPORTANTE: Utilice este script de prueba en su equipo de desarrollo. No lo pruebe en el servidor de producción de su proveedor de web hosting. Algunas rutinas de prueba podrían consumir demasiados recursos o incluso salirse de control si tienen fallas en la codificación. En su PC de prueba a lo sumo deberá hacer un reinicio, pero en un servidor de producción puede afectar el rendimiento de todos los sitios web alojados en el mismo y hasta hacerlo caer.
Copie el siguiente código y péguelo en un archivo que puede llamar test.asp:
<% @ Language = VBScript EnableSessionState = False %>
<%
'===========================================================
'Argentina-Hosting.Com --> http://www.argentina-hosting.com
'===========================================================
Option Explicit
Response.Buffer = True
'===========================================================
'Codigo para evitar el cacheo
Response.Buffer = True
Response.Expires = -1000
Response.ExpiresAbsolute = Now() - 1
Response.AddHeader "pragma","no-cache"
Response.AddHeader "cache-control","private"
Response.CacheControl = "no-cache"
'===========================================================
%>
<HTML>
<HEAD><TITLE>
MONITOR DE TIEMPO DE EJECUCION - Argentina-Hosting.Com
</TITLE></HEAD>
<BODY>
<%
Dim Comienzo, Fin
Comienzo = Timer()
%>
<%
'===========================================================
' Aquí comienza el código cuyo tiempo de ejecución se desea medir
Dim RS, i
For i = 1 to 10000
Set RS = Server.CreateObject("ADODB.Recordset")
Set RS = Nothing
Next
' Aquí termina el código cuyo tiempo de ejecución se desea medir
'===========================================================
%>
<%
Fin = Timer()
Response.Write("<b>Tiempo de Ejecución: " & 1000*(Fin - Comienzo) & " [miliSeg]</b>")
%>
</BODY></HTML>
tags: asp clasico, optimizar web, paginas web en asp, como optimizar una pagina web, optimizar sitio web, codigo asp clasico, asp 3.0, codigo asp 3.0, script asp clasico, script asp 3.0, asp tutorial en español, codigo asp
En esta sección encontrarás una mezcla de códigos recopilados de fuentes públicas de Internet y otros creados por ASP TEAM. Compartimos recursos útiles de buena fe para formar una base de conocimiento en el desarrollo de aplicaciones en ASP Clásico.