Concurrencias y Ajax

diciembre 3, 2009 • Publicado en Software y Hardware
Etiquetas:

La fortaleza que le ha valido a Ajax su puesto de supremacía entre las tecnologías de mayor crecimiento en Internet es la posibilidad de modificar el contenido de una página sin tener que refrescarla. Implementar un sistema con Ajax para actualizar la información de una página no representa mayores dificultades cuando se hace un único llamado, pero cuando se hacen múltiples comunicaciones, muchas de ellas sin esperar acuse de recibo, la situación requiere de algún método para regular las solicitudes.

La técnica convencional para regular el paso entre procesos es la declaración de un semáforo, un registro con el que los procesos determinan cuándo un recurso está siendo empleado y en qué momento está libre.

Para referencia presento a continuación la clase Semaphore implementada dentro del script del plugin minimax.

//Clase semáforo
function Semaphore() {
	var me = this;     //Para usar si una instancia de esta clase es 
                           // usada recursivamente.
	var status = true; //La luz verde (true) o roja (false). Inicia 
                           // en verde
	me.using = 0;      //Un contador para saber cuántas instancias 
                           // están usando este semáforo.

	//Poner semáforo en verde
	me.setGreen = function() {
		status = true;
	}

	//Está en verde?
	me.isGreen = function() {
		return status;
	}

	//Poner semáforo en rojo
	me.setRed = function() {
		status = false;
	}

	//Es rojo?
	me.isRed = function() {
		return !status;
	}
}

Antes de seguir con la implementación del semáforo hay que mencionar la capacidad que tiene Javascript para pasar por referencia un objeto en un llamado a una función, es decir, si lo que se envía en el llamado a la función es una instancia de una clase, cualquier modificación que se haga dentro de la función a dicha instancia se verá reflejado en la instancia con la que se llamó la función. Es decir, la instancia dentro de las variables con que se llama a la función y la instancia dentro de la función son la misma.

Usando esta capacidad se puede definir un semáforo común para las instancias de una misma clase. No olvide agregar la definición de la clase Semaphore antes de esta nueva clase.

//Clase car
function Car() {
	var me = this; //Para usar si una instancia de esta clase es usada
                       // recursivamente.

	me.semaphore = false;
	var haveSemaphore = false;

	//Funcción para declarar el semáforo
	me.setSemaphore = function(aux_semaphore) {
		haveSemaphore = true;
		semaphore = aux_semaphore;
		semaphore.setGreen();
		semaphore.using++;
	}
}

var semaphore = new Semaphore();

var car1 = new Car();
var car2 = new Car();
var car3 = new Car();

car1.setSemaphore(semaphore);
car2.setSemaphore(semaphore)
car3.setSemaphore(semaphore);

alert('El semáforo lo están usando '+semaphore.using+' instancias.');

El resultado de este script será una ventana con la leyenda «El semáforo lo están usando 3 instancias», lo que demuestra que el mismo semáforo ha sido llamado por cada una de las instancias de la clase Car.

Por lo general la idea de implementar un semáforo requiere que todo proceso que haya sido declarado para usarlo postergue su ejecución mientras el recurso que requiere para continuar no esté disponible. Nota: la siguiente función deberá estar dentro de la declaración de la clase Car para que logre su objetivo.

me.start = function () {
	//Si no hay semáforo o está en verde, llamar la función.
	//Sino, hacer otra solicitud en 300 milisegundos
	if( !haveSemaphore || semaphore.isGreen() ) {
		foo();
	} else {
		setTimeout(function (){ me.start(); }, 300);
	}
}

En lo que respecta a Ajax, cada vez que se vaya a iniciar una comunicación con el servidor se debe crear una nueva instancia de XHTMLRequest, porque en algunos motores de Javascript esta clase solo permite hacer un único llamado al servidor.

Para crear una instancia nueva se puede definir un método que pueda ser programada antes de usar open(), que es la función con que toda instancia de XHTMLRequest inicia la comunicación con el servidor.

var startXhr=function() {

	if (window.XMLHttpRequest) { // It it's Mozilla, Safari etc
		me.xhr = new XMLHttpRequest()
	} else {
		if (window.ActiveXObject) { // if it's IE
			try {
				me.xhr = new ActiveXObject('Microsoft.XMLHTTP')
			} catch (e) { // if it's and old version
				try {
					me.xhr = new ActiveXObject('Msxml2.XMLHTTP')
				} catch (e){}
			}
		} else {
			return false
		}
	}

	//Event handler when get the answer
	me.xhr.onreadystatechange = function() {
		//alert(me.xhr.readyState + ' ' + me.xhr.status);
		if (me.xhr.readyState == 4 && me.xhr.status==200 ) {
			var text=me.xhr.responseText;
			if(haveSemaphore) semaphore.setGreen();
			if(haveThrobber) throbber.close();
			if(div) document.getElementById(div).innerHTML=text;
		}
	}

}

startXhr();
me.xhr.open('POST', url, true);

Puede ver un ejemplo completo con estas técnicas en el script del plugin minimax. Ponga especial atención a la clase Semaphore, la declaración del método startXhr() y el llamado que se hace de él en las funciones me.get() y me.post().

Dejar un Comentario