Callbacks y funciones asíncronas, el estilo Node.js

El estilo nodejs

Yo pensaba que sabía -algo- de javascript hasta que descubrí Node.js :P. En fin, espero ser siempre un aprendiz. Conforme te vas asomando a nuevas tecnologías tratas de hacer las cosas correctamente y como recién llegado aplicas lo de donde fueres haz lo que vieres. ¿Existe algún documento con las convenciones de Node.js? Sí, Node.js tiene una guía de estilo aunque no es oficial. Pero ojo porque como se suele decir old habits are hard to break, y habrá cosas que igual te cuesten un poco, cosas tan simples como eso, las comillas simples/dobles, en fin... supongo que mucho de esa guía es debatible pero es lo que hay. De lo que si se habla es del preferred Node.js style que supongo que se resume seguir a los pros y a la comunidad en general. Cómo dice Felix, el autor de esa guía algunos de estos temas son religiosos. Todavía me parto con el inicio de la guía:
Let's start with the religious problems first. Our benevolent dictator (el pro de turno) has chosen 2 space indention for the node core, so you would do well to follow his choice..
Toda la guía se jaja de las discusiones y de los talibanes (también la guía tiene un tono ultra-ortodoxo) lo cual la hace muy simpática, a mi parecer. Otra perla:
Do not extend the prototypes of any objects, especially native ones. There is a special place in hell waiting for you if you don't obey this rule.

En fin, este tipo de polémicas entre programadores siempre han provocado oceanos de sangre...

Los concilios de programadores siempre acaban mal
No es solo cuestión de comillas y de camel case

Una de las cosas que chocan un poco al ir entrando en nodejs y en el javascript actual que todo lo invade es el tema de las llamadas asíncronas. Se estila el llamar a un método y establecer un callback para cuando ese método termine, cosa que por ejemplo se hace en el API de indexedDB. Y la cosa se puede complicar ya que puedes encadenar llamadas de callbacks cosa que puede llevarte a lo que se debe llamar callback spaghetti.

En el caso de que te vayas a meter en esos líos que sepas que en node dispones de módulos (Step, Async) que te permiten encadenar llamadas a funciones y además aplicar patrones asíncronos para que esas llamadas se hagan en cascada, en paralelo, en serie,... etc. Por ahora vamos a ver algo tan simple como dar soporte al callback.

Funciones de callback

Una de las principales recomendaciones de la guía de estilo de Node.js es que se utilicen funciones de callback ya que en definitiva las llamadas asíncronas son el alma de Node. En el siguiente ejemplo juego con un par de cosas: por una lado un método que puede recibir más de un parámetro y se preocupa de controlarlo y de paso muestra cómo controlar los tipos. Y por otro muestra cómo crear una función y que tenga soporte para un callback. Es tan simple como controlar que el último parámetro es de tipo función y nos debemos preocupar de dos cosas:

  1. Si hay error, el marrón se lo pasamos al callback.
  2. Si no hay error, lo último que hacemos en la función es llamar al callback pasándole el resultado.

/**
* callbacks.js
* variable arguments in function calls and
* function with callbacks
* @author Pello Xabier Altadill Izura
* @greetz 4 u
*/

/*
* example
* shows the use of variable arguments and how
* to deal with them. 
*/
function example (param1, param2) {
	console.log('example called. arguments: ' + arguments.length);

	for (i = 0; i < arguments.length;i++) {
		console.log('param ' + i + ': '+ arguments[i] + ". type: " + typeof(arguments[i]));
	}


	// check for argument types:
	// Check if first argument is an integer
	if (typeof(param1) !== 'number') {
		console.log('param1 is not a number: ');
	}

	// Check if second argument is a String
	if (typeof(param2) !== 'string') {
		console.log('param2 is not a string:');
	}

	console.log("All arguments are ok\n");

}

example();
example(5);
example(3,'6');
example('juan','perico','ejemplo');

/**
* sumWithCallback
* will sum two values and call the callback if any.
*/
function sumWithCallback(a,b) {

	// Is there any callback?
	var possibleCallback = arguments[arguments.length - 1];
	callback = (typeof(possibleCallback) == 'function' ? possibleCallback : null);

	// we mark the position of the last numeric argument depending of callback function presence
	var last = (callback == null)?arguments.length:arguments.length-1;

	// minium arguments: 1
	if (arguments.length < 1) {
		return callback(new Error("Please give me one argument."));
	}
	
	var result = 0;

	for (i=0;i<last;i++) {
		if (typeof(arguments[i]) !== 'number') {
			return callback(new Error('Argument ' + i + ' n(ot a number: ' + arguments[i]));
					} else {
						result += arguments[i];
					}
				}
			
	if (callback == null)
		return result
	else 
		return callback(null,result);
}

console.log(sumWithCallback(4,5,2));

// Now we call the same function with a callback
var result = sumWithCallback(600,66, function (err,data) {
					// throw error
					if (err)  throw err;

					console.log("result of operation: " + data);
					return data;
				});

console.log(result); 

by Pello Altadill 08/14/2013 22:08:41 - 1643 hits

Intents con parámetros y startActivityForResult

Cuando en Android queremos abrir una nueva pantalla o Activity se hace de una manera muy curiosa: se crea un Intent. Los Intent son eso, intentos. No garantizan que el resultado vaya a ser el correcto ni si quiera que alguien vaya a responder, y es que los intents se pueden usar tanto para abrir Activities como para solicitar cualquier cosa (iniciar una llamada, mandar un mensaje, etc... ). Con los intents en definitiva se llama a componentes de cualquier tipo. Pueden ser internos de la propia a...

by Pello Altadill 08/14/2013 12:57:24 - 758 hits

More »

Ejemplo de IndexedDB la BD de HTML5

HTML5 trae un montón de nuevas posibilidades al navegador. Se ha hablado mucho del formato de vídeo, del canvas, los websockets, de los nuevos controles de formulario pero a mí en particular me ha interesado especialmente aquello de una BD en el cliente. Es un tema que no está tan documentado como el resto y que en muchos libros de HTML5 o ni se menciona o se hace de pasada. Y lo que es peor, hay información en blogs pero a nada que esté desfasada los ejemplos no funcionan como la llamada a...

by Pello Altadill 08/13/2013 22:35:53 - 1676 hits

More »

Eventos en nodejs

NodeJS está orientado a eventos por tanto disponer de mecanismos para definir nuestros propios eventos es algo fundamental. Como vamos a ver no tenemos más que importar el módulo events y a partir de ahí ya podremos trabajar con instancias de EventEmitter. Y como disponemos de herencia, podemos agregar la emisión de eventos a nuestras clases. Un ejemplo sencillo de eventos Este programa lee datos por consola y puede generar tres eventos Si el usuario escribe algo S...

by Pello Altadill 08/13/2013 10:37:21 - 393 hits

More »

Consejos para programar Android

Desarrollar aplicaciones para Android no es tan ágil como con otras tecnologías. Montar la aplicación configurando cada uno de los ficheros XML (cosa que está bien pensada y tal) es un poco pesado y lo peor es que cuando lo quieres probar para ver el resultado tienes que esperar mucho y encima lo más seguro es que casque y que la aplicación se pare de forma inesperada. Voy a dejar aquí algunos consejillos que espero resulten útiles. ...

by Pello Altadill 08/13/2013 09:40:38 - 944 hits

More »

Hibernate self join con XML

El hecho de echar un ojo a SGBD noSQL no significa que lo relacional esté proscrito, por eso hay que seguir investigando más escenarios de hibernate. Existen situaciones en las que una tabla o entidad se hace referencia a sí misma. El ejemplo típico es el de empleado con un campo idjefe que hace referencia a otro empleado. Otro mítico se da en los foros, donde un mensaje puede tener un id de mensaje padre. Siguiendo con nuestro ejemplo del ERP vamos a ver cómo apañar el mapeo a si mismo con la ta...

by Pello Altadill 08/12/2013 14:26:02 - 571 hits

More »

Almacenamiento local en HTML5

Local Storage Los navegadores modernos van disfrutando de nuevas capacidades impulsadas por HTML5. Una de las más llamativas es la posibilidad del almacenamiento local, en el cliente, que viene en dos formas: por un lado en dos arrays relacionales que nos permiten guardar datos con un límite supuesto de 5Mb (al estilo del $_SESSION de php pero en el cliente) y por otra parte la posibilidad de tener una base de datos en el cliente. Está última, que un principio parecía iba a ser SQLite fina...

by Pello Altadill 08/11/2013 22:51:12 - 483 hits

More »

Leyendo por consola y herencia en nodejs

Para poder hacer cosas básicas en la consola con node tenemos un objeto predefinido llamado process que nos provee de todo los necesario, desde jugar con la stdin, stdout, stderr hasta terminar la ejecución. En un alarde de originalidad, aquí tienes una calculadora muy simple en la que se deben introducir dos números y un operador. /** * calc.js * Trying to code the good ol' calc with node event driven way * @author Pello Xabier Altadill Izura * @greetz for you *...

by Pello Altadill 08/11/2013 00:17:05 - 567 hits

More »

Hello nodejs

Hay gente que con la imposición vital esa de que hay que probar de todo va y se mete ketamina. Otros preferimos echar un vistazo a nodejs, en pleno viernes y después de haber visto Guerra Mundial Z. No estaba mal. Bueno, definiciones decentes de nodejs tendrás mejores, pero básicamente, aquel javascript que se supone que había para servidor ahora ya no es una especie de mito, a...

by Pello Altadill 08/10/2013 00:36:14 - 804 hits

More »