JQuery y Ajax

Cualquier librería actual que se precie debe tener un soporte completo de ajax, de la facilidad con la que maneje este importante y vital tarea vendrá buena parte de su éxito. Vamos a estudiar el soporte que tiene JQuery de ajax y como se desenvuelve en esta tarea.

Veamos como podemos lanzar una petición ajax directamente empleando sólo javascript

Para iniciar nuestro objeto ajax debemos emplear este código


var ajax;
if(window.XMLHttpRequest)
{
ajax = new XMLHttpRequest();
}
else if (window.ActiveXObject)
{
ajax = new ActiveXObject("Msxml2.XMLHTTP");
}
else
{
throw new Error("Este navegador no soporta ajax");
}

Es más complejo de lo que debería debido al soporte no estandar que le dio Microsoft es un navegador. A fin de cuentas Microsoft fue quien primero desarrollo esta tecnología.

Después de que la instancia ajax haya sido creada esta tiene una serie de métodos y propiedades que la dotan de funcionalidad. Todos los navegadores que soportan este objeto ajax tiene todos estos métodos/propiedades:

Métodos:

abort()
getAllResponseHeaders()
getResponseHeader(name)
open(method, url, async, username, password)
send(content)
setRequestHeader(name,value)

Propiedades:

onreadystatechange
readyState
reponseText
responseXML
status
statusText

Para lanzar una petición ajax debemos indicar el método a utilizar get o post, la URL a la que lanzar la petición, el cuerpo del mensaje si se trata de una petición POST (en el POST la información a enviar no viaja en la cabecera HTTP como con el método GET), si deseamos que la petición sea sincrona o no, autentificación si la URL lo precisa y una función callback para informar del progreso de la petición ajax.

el método open nos permite informar de la mayor parte de estos parámetros

ajax.open(‘GET’,’/url’);

Este método no lanza la petición, sólo la prepara

open(metodo,url,asincrono,usuario,password);

metodo – HTTP empleado, GET o POST, indica el tipo de formato empleado en la petición.
url – La url a solicitar.
asincrono – La petición debe ser asincrona, valor por defecto true, (no detiene la ejecución, básico en ajax) o sincrona (detiene ejecución hasta que se completa la tarea) valor a false.
usuario – Proporciona el usuario si es necesaria la autentificación.
password – Propociona un password si es necesaria la autentificación.

Ahora necesitamos informar cual será la función que se debe llamar cuando nuestra petición cambie de estado a través de la propiedad onreadystatechange. Debemos proporcionar una función para esta propiedad que será llamada varias veces después a medida que la petición ajax se vaya resolviendo para bien o para mal.

Podriamos definir esta función de esta manera

ajax.onreadystatechange = function ()
{
if(ajax.readyState == 4) //Estado terminado
{
if(ajax.status >= 200 && ajax.status < 300) //Sólo peticiones exitosas { // Código OK aquí } else //Peticiones que fallan { // Código de error aquí } } } Una cosa interesante, y muy desagradable, a tener en cuenta a la vista de este código es que la variable ajax es la del alcance global pero no es la variable pasada al controlador. Esto puede ser un problema si tenemos varias llamadas ajax activas simultáneamente. Tras hacer esto el último paso es lanzar la petición. Para ello llamamos al método send(content), cuyo parámetro es el contenido de la petición. Si es una petición GET no es preciso enviar nada
ajax.send(null);

En el caso de petición tipo POST debemos enviarle el contenido de la información que queremos enviar al servidor de manera debidamente formateada y URI-encoded, por ejemplo:

ajax.send(‘a=1&b=2&c=3’);

Como obtener la respuesta de la llamada

Esos tortazos tan entrañables

De vez en cuando no está nada mal ver una pequeña selección de esas cosas que pasan de vez en cuando, con el niño, el perro, la suegra, el vecino o uno mismo (¡me cachis!) y que tanto alegran el día a los otros (y que suelen ser muy recordados con el paso de tiempo).

¿Donde se había escondido el chino cudeiro?

y por último este video que me hizo partirme la caja hace algún tiempo.

Trucos para acelerar php

Vamos ha realizar un análisis crítico de este vídeo de Eric Higgins, webmaster de Google. En el vídeo nos cuenta alguno de sus trucos para acelerar sus scripts en php:

El primero de los trucos es emplear comillas simples en lugar de comillas dobles. Las comillas dobles hace que la cadena interprete un determinado número de secuencias de escape:

\n linefeed (LF or 0x0A (10) en ASCII)
\r retorno de carro (CR or 0x0D (13) en ASCII)
\t tabulación horizontal (HT or 0x09 (9) in ASCII)
\v tabulación vertical tab (VT or 0x0B (11) in ASCII) (since PHP 5.2.5)
\f form feed (FF or 0x0C (12) in ASCII) (since PHP 5.2.5)
\\ barra invertida
\$ signo de dolar
\” comillas dobles
\[0-7]{1,3} carácter en notación octal
\x[0-9A-Fa-f]{1,2} carácter en notación hexadecimal

Además de, por supuesto, expandir las variables que aparezcan en las cadenas.

En el caso de las comillas simples las únicas secuencias de escape reconocidas son estas dos:

\’ comillas simples
\\ barra invertida

Además de no expandir las variables en la cadena. Por todo ello es lógico pensar que una cadena con comillas simples será más rápida de procesar que una con comillas dobles, veámoslo con un código de ejemplo que después probaremos sin emplear ningún acelerador de php tipo APC o XCache:


echo '==Tests comillas dobles==',"\n";
for($j=0;$j<10;$j++)
{
$t1 = microtime(true);
for($i=0;$i<100000;$i++)
{
$a = "hola mundo";
}
$t2 = microtime(true);
$test1[] = $t2-$t1;
echo $t2-$t1;
echo "\n";
}

echo 'Valor medio: ',array_sum($test1)/($j-1),"\n\n\n";

echo '==Tests comillas simples==',"\n";
for($j=0;$j<10;$j++)
{
$t1 = microtime(true);
for($i=0;$i<100000;$i++)
{
$a = 'hola mundo';
}
$t2 = microtime(true);
$test2[] = $t2-$t1;
echo $t2-$t1;
echo "\n";
}
echo 'Valor medio: ',array_sum($test2)/($j-1),"\n";

Los resultados en mi vieja máquina son los siguientes:

==Tests comillas dobles==
1.2272200584412
1.2168197631836
1.2232639789581
1.2248270511627
1.2338960170746
1.2382409572601
1.5701949596405
1.4171171188354
1.251455783844
1.2365839481354
Valor medio: 1.4266244040595

==Tests comillas simples==
1.2352590560913
1.1931908130646
1.2339069843292
1.2618341445923
1.2174820899963
1.2468011379242
1.2535820007324
1.2457919120789
1.3603079319
1.3120169639587
Valor medio: 1.3955747816298

Parece pues que estamos en lo cierto las comillas simples son más rápidas que las dobles como cabría esperar.

Pero vamos a invertir el orden de las pruebas, empezando ahora por las comillas simples, este es el resultado:

==Tests comillas simples==
1.2222979068756
1.2254979610443
1.2982668876648
1.1845409870148
1.2094640731812
1.1939878463745
1.153324842453
1.2170951366425
1.1506760120392
1.1662788391113
Valor medio: 1.3357144991557

==Tests comillas dobles==
1.2285170555115
1.1904451847076
1.1701879501343
1.184662103653
1.1987600326538
1.1889038085938
1.190358877182
1.1833288669586
1.1585729122162
1.2015302181244
Valor medio: 1.321696334415

¿Como? ¡Las comillas simples con más lentas ahora! en contra de toda nuestra lógica. Después de repetir los tests un buen número de veces estos resultados siguen repitiéndose. Parece que la primera prueba es más lenta que la segunda sin importar que sean comillas dobles o simples. Incluso después de probar repetidas veces el orden de las pruebas no se ha observado ninguna variación.

Vamos ahora con la prueba de la concatenación con print y el echo sin concatenación.

Este es el código para poder ejecutar las pruebas (he empleado output buffering para no volcar por pantalla todos esas decenas de miles de cadenas):


Resultado:

==Print concatenado==
3.2009110450745
3.1793689727783
3.2047038078308
3.1655762195587
3.1424939632416
3.0726661682129
3.2378449440002
3.4216639995575
3.5003128051758
3.1557071208954
Valor medio: 3.5868054495917

==Echo sin concatenación==
3.1254539489746
3.0349171161652
2.9997961521149
2.9809520244598
2.9241809844971
3.1526489257812
2.9299869537354
2.9526100158691
2.9198181629181
2.9321920871735
Valor medio: 3.3280618190765

Invirtiendo las pruebas para comprobar que el orden no afecta al resultado

==Echo sin concatenación==
3.0520401000977
3.184662103653
2.8883378505707
2.8706419467926
3.0163989067078
2.8317699432373
2.856645822525
2.871414899826
2.8769338130951
2.7966349124908
Valor medio: 3.2494978109996

==Print concatenado==
2.8693239688873
2.9165189266205
2.8810060024261
3.0247449874878
2.8426420688629
2.8691411018372
2.8807561397552
2.8754470348358
2.8367080688477
2.8549909591675
Valor medio: 3.2056976954142

La conclusión es que las pruebas no son relevantes y que en estos casos tan sencillos la mejoras en rendimiento no son significativas.

Repitamos las pruebas para cadenas más complejas. Por ejemplo, para la prueba de concatenación con print contra echo y varios argumentos substituimos la línea de echo por:

echo 'h','o','l','a',' ','m','u','n','d','o';

y la de print por:

print 'h'.'o'.'l'.'a'.' '.'m'.'u'.'n'.'d'.'o';

En este caso la mayor velocidad es para el echo no concatenado sin importar el orden. Uno de los tests por ejemplo arrojó estos datos:

Valor medio: 3.6208234363132 (echo)
Valor medio: 3.7140626907349 (print)

Repitiendo varias veces la pruebas y variando el orden el resultado se confirma. Eric Higgins estaba en lo correcto. Aunque con algunos peros, en los casos más simples no se observa mejoras de rendimiento.

Para el caso de las comillas dobles contra las simples debemos modificar las cadenas pero es complejo crear dos cadenas equivalentes que no desvirtúen la prueba. Lo ideal sería emplear sustitución de variables y/o secuencias de escape pero al sólo poder emplearla en una de las dos pruebas no podemos usar formas equivalentes. Lo mejor en este caso es seguir la lógica y emplear las comillas simples en donde podamos. Pero esto da lugar a modificaciones en las cadenas y a operaciones de concatenación extra. ¿Cuál es la mejor solución?. Bien provémoslo:

Siendo
$hola = 'hola';
$mundo = 'mundo';

Intentaremos probar que es mas rápido:

$a = "$hola $mundo";

ó

$a = $hola.' '.$mundo;

Esta prueba si que es más realista y aparece en multitud de ocasiones, en diversas variaciones, en muchos scripts reales.

Los resultados si que son relevantes en este caso, modificando el orden de las pruebas la segunda opción con las comillas simple es siempre más rápida en todas nuestras pruebas sin importar el orden.

Por lo tanto nos ratificamos: la comillas simples son mejores (por lo menos con este nivel de concatenación/sustitución de variables) aunque haya que emplear concatenaciones adicionales a la opción con dobles comillas. Le volvemos a dar la razón a Eric Higgins pero con más peros.

Pruebas realizadas con la siguiente configuración

Versión de php: 5.2.5

Arquitectura/CPU:
processor : 0
vendor_id : AuthenticAMD
cpu family : 15
model : 44
model name : AMD Sempron(tm) Processor 2600+
stepping : 2
cpu MHz : 1596.502
cache size : 128 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt lm 3dnowext 3dnow up pni lahf_lm ts ttp tm stc
bogomips : 3194.83
clflush size : 64

kernel: Linux 2.6.24.3-custom
Sistema operativo: Ubuntu 9.04 - Jaunty Jackalope (Abril 2009)