Curso de




Día 3: Continuaciones y 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


Ideal para llamadas asíncronas

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


¿Son los GOTOs modernos?

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


Promesas


Programación reactiva


Generadores: casi listos


Corutinas: falta bastante todavía

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!





Curso de Node.js Amaris: Callbacks

By Alex Fernández

Curso de Node.js Amaris: Callbacks

Curso para Amaris de Node.js, 2014-11-05: continuaciones y callbacks

  • 1,486

More from Alex Fernández