meets
callbacks
Vuestro anfitrión
(según mi hija de 5 años)
Ingeniero senior en MediaSmart Mobile
Co-organizador de Node.js Madrid
@pinchito
Guión
- Continuaciones
- Sesión práctica: objetos
- Callbacks
- Sesión práctica: eliminando callbacks
Continuaciones
Continuation-Passing Style
Continuaciones
Concepto de programación funcional
CPS: Continuation-passing Style
¡También conocidas como callbacks!
El estado pasa como parámetros y clausuras
Ejemplo: servidor sockets
var net = require('net');
var port = 1702;
var server = net.createServer(function(connection) {
console.log('Connection to %s open', port);
connection.write('Hello?\r\n');
connection.on('data', function(data) {
if (String(data).trim() != 'hello) {
connection.write('ERROR\r\n');
} else {
connection.end('world\r\n');
console.log('Connection to %s closed', port);
}
});
});
server.listen(port);
Continuaciones en amarillo
Parámetros en negrita
Clausuras en celeste
Otra visión de lo mismo
var net = require('net');
var port = 1702;
var server = net.createServer(function(connection) {
console.log('Connection open');
connection.write('Hello?\r\n');
connection.on('data', function(data) {
if (String(data).trim() != 'hello') {
connection.write('ERROR\r\n');
} else {
connection.end('world\r\n');
console.log('connection closed');
}
});
});
server.listen(port);
Contiene tres niveles de ejecución
ASYNC
Librería para ejecución asíncrona
Basada en continuaciones
-
async.series()
: corre las funciones una tras otra
-
async.parallel()
: corre las funciones a la vez
-
async.waterfall()
: pasa el resultado de una a otra
Fuente: async
Async.series()
Ejemplo:
// an example using an object instead of an array async.series({ one: function(callback){ setTimeout(function(){ callback(null, 1); }, 200); }, two: function(callback){ setTimeout(function(){ callback(null, 2); }, 100); } }, function(err, results) { console.log('Results: %j', results); });Fuente: async
Sesión Práctica 1: async
Usa el módulo async para leer una serie de valores
y sumarlos
¡Cuidado con las clausuras!
Especificación técnica
Hay que leer todos los ficheros:
- http://stats.mediasmart.es/bulk/test-2014/account-01.json
- ...
- http://stats.mediasmart.es/bulk/test-2014/account-05.json
Para cada uno debe parsear el JSON,
leer el campo "Debt",
y acumular todos los valores
Ejemplo
Lectura de un JSON:
var request = require('request'); var url = 'http://stats.mediasmart.es/bulk/test-2014/account-01.json'; request(file, function(err,res,body) { if (!err && res.statusCode==200) { body = JSON.parse(body); console.log('Debt: %s', body.Debt); } });
Generalizar a 5 ficheros
Función de segundo orden
Función que devuelve una función (que lee el JSON):
var request = require('request'); function getDebtReader(url) { return function(callback) { request(file, function(error, result, body) { if (error || result.statusCode != 200) { return callback('Could not read ' + url); } body = JSON.parse(body); return callback(null, body.Debt); }); }; }
¡bien!
Callbacks
Introducción al "infierno" de las callbacks
Pruebas de simplecached
'use strict'; var client = require('./lib/client.js'); var options = { port: 11311, host: 'localhost' }; var client = new client.Client(options, function(error) { console.assert(!error, 'Could not open connection'); var key = 'testing'; var value = 'real value'; client.set(key, value, function(error, result) { console.assert(!error, 'Error setting key'); console.assert(result, 'Could not set key'); client.get(key, function(error, result) { console.assert(!error, 'Error getting key'); console.assert(result == value, 'Invalid get key'); client.delete(key, function(error, result) { console.assert(!error, 'Error deleting key'); console.assert(result, 'Could not delete key'); client.close(function(error) { console.assert(!error, 'Error closing client'); }); }); }); }); });
Fuente: simplecached
Infierno de las Callbacks
La temida pirámide de callbacks
Infinitas continuaciones anidadas
Abuso de lambdas (funciones anónimas)
Difícil de seguir, depurar y refactorizar
Soluciones Sencillas
Usar funciones con nombre
Crear un objeto con funciones con nombre
Las clausuras se convierten en atributos
Usar async: async.waterfall()
Usar eventos: EventEmitter
Otros modelos
Sesión práctica 2: desmontando callbacks
Revisar la pirámide de callbacks
Código original: servidor de sockets
Convertir a objeto con atributos
No dejar dos callbacks anidadas
servidor sockets
var net = require('net');
var port = 1702;
var server = net.createServer(function(connection) {
console.log('Connection to %s open', port);
connection.write('Hello?\r\n');
connection.on('data', function(data) {
if (String(data).trim() != 'hello) {
connection.write('ERROR\r\n');
} else {
connection.end('world\r\n');
console.log('Connection to %s closed', port);
}
});
});
server.listen(port);
Continuaciones en amarillo
Parámetros en negrita
Clausuras en celeste
Ejercicio
Revisar la pirámide de callbacks
Código original: test de simplecached
Convertir a objeto con atributos
No dejar más de dos callbacks anidadas
¡Bien!
Thanks!
IronHack meets Node.js: Callbacks
By Alex Fernández
IronHack meets Node.js: Callbacks
Curso para IronHack de Node.js, 2015-05-06: continuaciones y callbacks
- 2,697