Contenido

Carga asíncrona de grandes cantidades de dátos con Ajax

22 Mar

+ 31

Ajax es una técnica para cargar asíncronamiente datos que podremos usar en nuestras páginas web. Esta técnica ha permitido a las aplicaciones web que evolucionen hasta el nivel actual y darán lugar a nuevas aplicaciones más potentes y complejas.

Esta técnica se basa en el uso de xmlhttprequest() para lanzar llamadas de forma asíncrona al servidor, pudiendo así devolver datos cargados posteriormente a la carga de la página. De esta forma la carga inicial de la página puede ser menor y dejar a elección del usuario cargar los datos a medida que los vayan necesitando.

El problema no lo encontramos con la cantidad de datos. Si el número de datos devueltos por el servidor es muy alto esto suele convertirse en una larga espera, con el fichero .gif de loading reglamentario.

Para intentar mitigar este problema he estado haciendo una serie de pruebas, con fín de dejar los ficheros XML que hasta ahora he estado usando en algunos proyectos.

XML

Durante mucho tiempo ha sido el sistema usado en muchas implementaciones para obtener datos de forma asíncrona. De ahí el propio nombre de AjaX (Asynchronous JavaScript And XML). Estos ficheros, generalmente ofrecen mayor interconexión con multiples herramientas.

En un uso para carga asíncrona, nos encontramos como príncipal problema el peso del fichero y tiempo invertido en recorrer el fichero XML para obtener los datos.

....
<hotel>
	<code>0000</code>
	<name>Hotel0</name>
	<direction>Calle0</direction>
	<telef>Telf0</telef>
	<geo>
		<lat>00</lat>
		<lng>00</lng>
	</geo>
</hotel>
....
// Javascript
var hotelDescription = data, hotelList = [];
var data = data.getElementsByTagName("hotel");
for (var x in data) {
	var hotel = data[x];
	if (!hotel.getElementsByTagName) continue;
	hotelList.push(hotel.getElementsByTagName("name")[0].firstChild.data);

		hotelDescription[hotel.getElementsByTagName("name")[0].firstChild.data] = {
			code: hotel.getElementsByTagName("code")[0].firstChild.data,
			name: hotel.getElementsByTagName("name")[0].firstChild.data,
			direction: hotel.getElementsByTagName("direction")[0].firstChild.data,
			telf: hotel.getElementsByTagName("telef")[0].firstChild.data,
			geo: {
				lat: hotel.getElementsByTagName("lat")[0].firstChild.data,
				lng: hotel.getElementsByTagName("lng")[0].firstChild.data
			}
		};

}

JSON

La primera alternativa, fué JSON, una implementación muy clara y natural de mostrar datos. Al tratarse de un fichero TXT podemos hacer que ocupe menos espacio y al evitar la estructura XML conseguimos que el tiempo invertido en recorrer el XML para obtener los datos.

Pero por contra, para poder usar los datos obtenidos hemos de usar la función eval() lo que nos penaliza la carga del fichero. Una vez evaluado el código el tiempo empleado en preparar los datos para poder usarlos es mínimo y sin duda, el más rápido de los sistemas exáminados.

....
{
	code: 0000,
	name: 'Hotel0',
	direction: 'Calle0',
	telef: 'Telf0',
	geo: {
		lat: 00,
		lng: 00
	}
}
....
// Javascript
var hotelDescription = data, hotelList = [];
for (var x in data) hotelList.push(data[x].name);

TXT

La gente de Flickr comentaba hace poco como hicieron para devolver más de 10.000 resultados en menos de 200ms. Y obviamente me ví obligado a contemplar esta técnica.

Se basa en usar una estructura preestablecida en un fichero de texto plano. Usando un separador por registro y otro por campos dentro de cada registro. De esta forma a la hora de cargar el fichero simplemente tendremos que hacer una serie de split() para cortar la cadena y convertirla en una variable que podamos usar.

Como mayor ventaja, esta técnica ofrece un tamaño de fichero mucho más pequeño que los comentados anteriormente. Por contra el tiempo de proceso sobre los datos para obtener una variable que pdamos usar es mucho mayor que la necesaria para procesar el fichero JSON, pero bastante menor que el empleado para un fichero XML.

0000:Hotel0:Calle0:Telf0:00:00|...
// Javascript
var tmp = data.split("|");
var hotelList = [];
var hotelDescription = [];
for (var x = 0, len = tmp.length; x<len; x++) {
	var hotel = tmp[x].split(":");

	hotelList.push(hotel[1]);

	hotelDescription[hotel[1]] = {
		code: hotel[0],
		name: hotel[1],
		direction: hotel[2],
		telf: hotel[3],
		geo: {
			lat: hotel[4],
			lng: hotel[5]
		}
	};
}

Comparativas

Para las pruebas, he realizado una pequeña aplicacion que nos permite cargar 500, 1000, 2000, 5000 o 10000 registros en los formatos anteriores (XML, JSON o TXT). Para los gráficos he usado los resultados obtenidos en Firefox 3.0.7 en Mac Os X.

Si queréis podéis probar por vosotros mismos los resultados que obtendríais en diferentes navegadores directamente aqui.

500 registros

500_registros

1000 registros

10000_registros

2000 registros

2000_registros2

5000 registros

5000_registros

10000 registros

10000_registros

Parece que los gráficos hablan por si solos, y podemos sacar una información interesante.

Conclusiones

bigajax

De los resultados obtenemos las siguientes premisas:

XML

  • Son los ficheros más pesados
  • El tiempo de procesamiento es mayor que los demás.

JSON

  • Son los ficheros que más tiempo tardan en cargar completamente.
  • El tiempo de procesamiento es el más rápido de los testeados.

TXT

  • Son los ficheros menos pesados.
  • El tiempo de proceso y carga son bajos aunque no destacan frente a los demás.
  • El tiempo total es el menor de los testeados.

Descargar el proyecto

He subido el proyecto a Github para que los descargueis y usais si quereis.

  • He hecho las pruebas en la demo y la verdad que obtengo resultado totalmente diferentes a los tuyos, ¿no tendrías cacheados los *txt y *xml?

    En mis resultados, en tiempo de descarga siempre gana txt, seguido de lejos por json y finalmente xml (esto es de cajón, es proporcional a su tamaño). Y en tiempo de procesamiento, resultados también obvios, json primero (es lo que tiene que sea ya js :P), seguido por texto plano y finalmente muy lejos, xml.

    En definitiva, json gana salvo en casos muy simples, como éste, en los que usar texto plano no es un excesivo dolor.

  • @blaxter lo que pasa es que la función eval() no se por que es muy lenta, tal y como explican en el articulo ese de flickr.

    Sin embargo, si usas el tag es mucho mas rápido, o si usas un analizador de json nativo (https://developer.mozilla.org/web-tech/2009/02/17/native-json-in-firefox-31/), que seria lo mas rápido de todo (probablemente bastante mas rápido que el txt para grandes cantidades de datos).

    P.D: Anieto2k: me acabo de dar cuenta de que tienes comandos para ubiquity, voy a probarlos 😉

  • @YouWoTMA: Me estoy refiriendo al tiempo de carga que es lo que tarda en llamarse la función de callback desde que realizas la petición, vamos la simple descarga del fichero principalmente.

    Es decir, que las gráficas de tamaño y tiempo de carga deberían de ser proporcionales.

  • ¿Cuál es entonces el recomendado? ¿JSON o TXT?
    ¿O cuándo uno y cuando el otro?
    Gracias

  • @blaxter: Me intenté asegurar de que no se cachearan, pero si lo hubieran hecho los *json deberían haberse cacheado igual.
    @YouWoTMA: json nativo, sería lo idea. La unión de fuerzas 😀
    @Gabriel Porras: Personalmente creo que debes sopesar para que lo vas a usar. Si ese fichero es para un uso personal e interno, osea que no vas a compartir los datos con nadie más, el TXT es la mejor opción. Es más a Flickr les está funcionando perfectamente.

    Pero si quieres un poco más de compatibilidad tendrás que usar XML o JSON, perdiendo velocidad. Hasta que, como dice YouWoTMA, no tengamos json nativo en los navegadores no podemos tenerlo todo.

  • Excelente información! Andrés, ya nos contarás cómo optimizaste la recuperación de tantos puntos con Google Maps.

  • Lo estoy probando en varios navegadores(ff 3.0.7, chrome 2.0.169.1, opera 10, ie8) y mis resultados son similares a los que expone blaxter, excepto en ie8 que da error con xml.

  • @Punkesito: Pues es raro, yo acabo de hacer pruebas con Firefox 3.0.7, Safari4, Chrome, Opera 9.6 e Internet Explorer 7 (con error incluido) y el formato TXT es es más rápido con diferencia.

    He añadido un sistema para comparar los resultados mediante cookies.

  • Excelente aportación, como casi siempre (*).

    Una pregunta. ¿Qué diferencia habría si los datos individuales que se intentan devolver son de un gran tamaño? Por ejemplo, un campo txt que contenga un artículo o descripción. Ya que por lo que veo en el ejemplo, no creo que exista un campo mayor a una línea de 256 carácteres a lo sumo.

    He leído en alguna página que JSON tenía un límite a la hora de devolver dichos datos y que no lo hacía de forma completa, ¿alguien me puede aclarar si es cierto?

    * es para que no te lo creas y sigas trabajando igual.

  • Voy a realizar una aplicación web que como munición de datos principal usa xml para modelizar y describir procesos industriales (estoy hablando de xml bastante grandes)… Sería recomendable que asp.net (es lo que usamos) se encargase de hacer una transcripción xml a json? Existe un transcriptor semejante? Es transformable 100% xml en json sin perder información? Gracias

    Magnifica web.

  • Me sorprende que un split sobre varios registros sea más lento que un eval de un json en navegadores medianamente modernos…

    Entiendo que calculas como tiempo de carga el tiempo que pasa desde que pides la información hasta que tienes el objeto/array listo para usarse (contemplando tanto transformacion del xml, como el eval, como el split).

    De todas formas, salvo para cosas muy puntuales (desarrollos de aplicaciones web y no páginas) yo usaría antes json que txt.
    Entiendo que este artículo va dirigido a grandes cargas de grandes cantidades de datos para webs de alto volumen de tráfico y en ese caso estas mediciones si que tiene sentido.

    Explico mi preferencia. Json nos permite ver claramente donde estamos metiendo cada dato, es escalable sin problemas puesto que podemos ir añadiendo más objetos cada vez y organizarlos en varias dimensiones, un solo json nos sirve para cargar distintos contenidos y por ultimo usando jsonP podemos facilmente hacer un webservice con nuestros jsons…

    Eso unido a que ya se ha anunciado que javaScript terminará teniendo nativa la carga de jsons nos lleva a que por lo general es mejor usar json (aunque el eval ahora mismo tarde más). Estandarizar siempre es bueno.

  • @ikhuerta: No lo entiendo. ¿Soy el único que obtiene resultados en los que json es mucho más lento que txt?

  • No no, yo no lo he probado. Solo digo que me sorprende ya que tenía entendido que el split al contemplar de serie expresiones regulares tampoco era el no va más en rendimiento… 😉

    —–

    El resto de mi comentario iba más en cuanto a que está bien ver velocidades de proceso en js cuando hablas de cantidades industriales de datos… pero hay demasiados puntos a favor de json como para descartarlo solo por ser «un poco más lento» en la mayor parte de las aplicaciones que podemos darle a Ajax…

    Perdona por mezclar.

  • @ikhuerta: No es mi intención descartar JSON, solo intentaba comparar las diferentes posibilidades.

    Ell único problema que le he encontrado a JSOn es que al evaluar toda la cadena de una tacada con eval() en «cantidades industriales» el navegador se queda un poco «lelo» y nos solicita ternar el proceso.

  • Excelente información, estos son los resultados en mi firefox 3.6a1pre.

    500 xml : 1464ms.
    500 json : 1225ms.
    500 txt : 735ms.
    1000 xml : 2176ms.
    1000 json : 1648ms.
    1000 txt : 1415ms.
    2000 xml : 3516ms.
    2000 json : 2267ms.
    2000 txt : 933ms.
    5000 xml : 8133ms.
    5000 json : 5136ms.
    5000 txt : 2126ms.
    10000 xml : 14212ms.
    10000 json : 9909ms.
    10000 txt : 3622ms.

  • Hola
    Pero porke el JSON tarda en cargar exageradamente mas ke el XML, si tiene mucho menos caracteres para transmitir ke el XML

  • @Daniel: Principalmente por que json es un texto plano que debemos pasar a una variable de Javascript. En cambio XML es una estructura que el objeto xmlhttprequest() ya conoce y devuelve preparado para navegar por él.

  • Uh… parece que se les olvidó algo.

    JSON es un string común y corriente, tal como el utilizado en la prueba TXT, solamente que mas pesado.

    En este caso se utilizó la funcion eval(), pero perfectamente se puede parsear un String JSON con la funcion split().

    Saludos.

  • Buenas.. y me pregunto… al igual es una pregunta muy tonta, pero usando el método por TXT plano si en los datos correctos a extraer tiene la cadena clave para la extracción con split?

    Es decir si tenemos algo como …

    0001: el gran hotel : MonteConquero : C:/ rivas nº4 | …

    Aqui saca mas campos de la cuenta ya que se pretende que solo se extraiga:

    Codigo: 0001
    Hotel: el gran hotel : MonteConquero
    Descripcion: C:/rivas nº4

    Es decir que este método no es ideal ya que se puede cometer errores ya hay que decidir al menos dos carácteres especiales y nunca se sabe que puede meter el usuario aunque parseemos esos carácteres…

    De momento me quedo con JSON…

    Saludos desde Onuba…

  • ¿Porqué tarda tanto la carga en JSON y no en TXT? Porque es lo que dice @Andrés Pontt, ¿porqué no se utiliza una función split sobre JSON y entonces el rendimiento completo de JSON sería el mejor?

  • @peter: Tendríamos un problema. Por eso se recomienda usar patrones más dificiles «\aa» o «a\a» o lo que la imaginación dé 😀
    @david: No le veo sentido a parsear un JSON con split(). ¿Que sentido tiene enviarnos JSON directamente el servidor si luego lo vamos a parsear con split() y trabajar con él como si fuera texto plano? Mejor pasarnos el texto plano para hacer uno o dos splits ¿no?

    De todas formas, el uso de JSON, y la ventaja principal que podemos destacar es que en todos los lenguajes hay aplicaciones o implementaciones nativas para trabajar con él sin necesidad de modificar nada, simplemente usarlo y listo.

    De esta forma el JSON, pide el reemplazo del XML. Pero no por ello tiene que ser más rápido.

    En el artículo no pretendo decir que JSON es peor o TXT es mejor, simplemente informar de que tenemos otras opciones y que dependiendo de la necesidad y las condiciones del proyecto, podemos optar por unas u otras.

    En mi caso, necesito mostrar cerca de 5800 registros en un suggest, y despues de todas las pruebas que he hecho, la mejor opción (para mi proyecto) es usar el formato TXT.

    Pero única y exclusivamente para esta tarea, las demás se van a quedar con JSON que es más fácil de interconectar con otras aplicaciones 😀

  • Muy interesante! Gracias.

    Por cierto, la gráfica de 1.000 está mal, en su lugar está la de 10.000.

    Para aclarar un poco: tal como dices en el artículo el tiempo de carga en el caso de JSON incluye el uso de la función eval(), además de la descarga del archivo, no? por eso sus resultados son peores en cuanto a carga a pesar de poseer el tamaño de archivo medio.

  • Reitero apelando a la lógica y sentido común, que las gráficas son incorrectas, al menos en todos los navegadores que he probado (opera/konqueror/firefox bajo linux), txt es el más rápido, pero json le sigue de cerca y xml el último como es natural.

  • @blaxter: Pues es raro, yo en todos los que he probado bajo Windows/Mac siempre he obtenido resultados similares a los de las gráficas.

  • OT: peter, el ejemplo que has puesto es erróneno … el monteconquero no está en calle rivas 🙂

Comentar

#

Me reservo el derecho de eliminar y/o modificar los comentarios que contengan lenguaje inapropiado, spam u otras conductas no apropiadas en una comunidad civilizada. Si tu comentario no aparece, puede ser que akismet lo haya capturado, cada día lo reviso y lo coloco en su lugar. Siento las molestias.