Implementando colas de ejecución en JavaScript


Para una implementación más completa, ver la entrada ‘QueQue: Colas de ejecución‘.


 

Para los despistados, una cola ejecución es básicamente una estructura que nos asegura la ejecución secuencial de los bloques deseados. Esto es útil en el caso de implementar pasos asíncronicos, donde el anidamiento de funciones anónimas puede bien, no adaptarse a las necesidades o convertir la sintaxis en un calvario (caso más común).

// Tarea sincronica
doTheFirstThing();
// Tarea asincronica
ajax('/get', function(result) {
	// Tarea sincronica
	doTheThirdThing();
	// Tarea asincronica
	ajax('/validate', function() {
		// ...
	});
});

Entonces, la idea básica de la cola (queue) es agrupar tareas y ejecutarlas una por una (como dijimos, secuencialmente) a fines de respetar un orden requerido para la correcta funcionalidad de la aplicación, indistintamente del tipo de tareas (síncronicas o asíncronicas).

Ejecución secuencial

Ejecución secuencial

Nuestra implementación (bastante básica) de cola constará de 3 (tres) métodos, add, process y clear. El primero agregará la tarea, el segundo ejecutará TODAS las tareas agregadas en el ordenque fueron agregadas, y el último las borrará de la cola.

En primera instancia generamos el constructor, con elpattern constructor típico de JavaScript:

/**
 * Cola básica
 *
 * @constructor
 */
var Queue = function() {
	this._tasks = [];
};

Acto seguido, agregamos los métodos que tendrá el constructor, inicialmente, el método add:

/**
 * Agrega una tarea (function) a la cola
 *
 * El argumento scope indica en que objeto debe
 * ejecutarse el metodo (por defecto es el contexto
 * global).
 *
 * @param {Function} fn
 * @param {Object} scope
 * @return {Queue}
 */
Queue.prototype.add = function(fn, scope) {
	this._tasks.push({
		fn: fn,
		scope: scope
	});
	// Devolvemos la instancia para poder agregar
	// en cadena
	return this;
};

El método clear es bastante sencillo:

/**
 * Elimina las tareas activas de la
 * cola
 *
 * @return {void}
 */
Queue.prototype.clear = function() {
	this._tasks = [];
	// Devolvemos la instancia para poder agregar
	// en cadena
	return this;
};

Finalmente, el método process, requiere un poco más de código:

/**
 * Inicia la ejecución de la cola
 *
 * @return void
 */
Queue.prototype.process = function() {
	var proxy, self = this;

	// Obtenemos la primer tarea activa
	task = this._tasks.shift();

	// Si no existe, nada mas para hacer
	if(!task) {
		return;
	}

	// Creamos un proxy para que la tarea
	// puede indicarle a la cola que ha
	// finalizado su trabajo
	proxy = {
		end: function() {
			self.process();
		}
	};

	// Ejecutamos la tarea en el contexto
	// establecido (o el global pordefecto)
	task.fn.call(task.scope, proxy);
	// Devolvemos la instancia para poder agregar
	// en cadena
	return this;
};

Este constructor, permitira que sus instancias gestionen colas independientes de la siguiente manera:

// Instanciamos una nueva cola
var queueTest = new Queue();

// Tarea 1 (sincronica)
queueTest.add(function(proxy) {
	// logica especifica

	// Finalizamos la tarea
	proxy.end();
});

// Tarea 2 (asincronica)
queueTest.add(function(proxy) {
	setTimeout(function() {
		//logica especifica

		// Finalizamos la tarea
		proxy.end();
	}, 2500);
});

// Tarea 3 (sincronica)
queueTest.add(function(proxy) {
	//logica especifica

	// Finalizamos la tarea
	proxy.end();
});

// Inicia la ejecución
queueTest.process();

En este link puede verse la cola en funcionamiento.

Obviamente, esta implementación solo sirve a fines didácticos. Este mismo constructor puede ser mejorado con eventos (por ejemplo onTaskComplete, onComplete, etc), error handlers, pasar resultados a las siguientes tareas, etc.

Una librería que realiza un trabajo similar (y más) es Step de creationix, disponible para Node (pero implementable en otros entornos).

Leer más:


Shortlink: http://goo.gl/dm2ze


	task.fn.call(task.scope, proxy);


2 views shared on this article. Join in...



Pings to this post

  1. […] ejemplo más real, se puede ver en una de las entradas anteriores, en la cual se implementa una cola de […]

  2. […] librería que surgue con motivo de ampliar el ejemplo de una entrada anterior (en la cual vimos como implementar una cola básica de ejecución) . La idea es básicamente ejecutar un conjunto de métodos en un orden dado y compartiendo cierta […]


Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Comment

You may use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>