Vous êtes sur la page 1sur 53

Programacin

Asncrona en
Node JS
Modelo de Paso de Con,nuaciones, Eventos,
Promesas y Generadores

Javier Vlez Reyes

@javiervelezreye

Javier.velez.reyes@gmail.com

Mayo 2014

Programacin Asncrona en Node JS


Presentacin
I. Quin Soy?

Licenciado en inform2ca por la Universidad Politcnica de


Madrid (UPM) desde el ao 2001 y doctor en inform2ca por la
Universidad Nacional de Educacin a Distancia (UNED) desde el
ao 2009, Javier es inves2gador y est especializado en el diseo
y anlisis de la colaboracin. Esta labor la compagina con
ac2vidades de evangelizacin, consultora, mentoring y formacin
especializada para empresas dentro del sector IT. Inquieto, vido
lector y seguidor cercano de las innovaciones en tecnologa.

E-learning
Diseo de Sistemas de Colaboracin
Learning Analy2cs
Gamicacin Colabora2va
Diseo Instruccional

1-2

II. A Qu Me Dedico?

Desarrollado Front/Back
Evangelizacin Web
Arquitectura SoZware
Formacin & Consultora IT

@javiervelezreye

Introduccin

Programacin Secuencial
Programacin Asncrona
Modelos de Programacin Asncrona
Un ejemplo

Introduccin

1
Javier.veler.reyes@gmail.com

Programacin Asncrona en Node JS

Javier Vlez Reyes


@javiervelezreye

Programacin Asncrona en Node JS


Introduccin
I. Programacin Secuencial

Tradicionalmente, el modelo de ejecucin que u2lizan la mayora de los lenguajes y


paradigmas de programacin se corresponde con un tratamiento secuencial del cuerpo del
programa. Un programa es entendido como una secuencia de instrucciones que se ejecutan
ordenadamente y donde la ejecucin de cada operacin no da comienzo hasta que no termina
la anterior.

Operaciones bloqueantes
Se dice que las operaciones son bloqueantes ya
que bloquean el ujo de ejecucin del programa
llamante impidiendo que la siguiente instruccin
comience hasta que la anterior haya terminado

Razonamiento basado en estado


Con este esquema resulta fcil razonar acerca
del comportamiento del programa si ste se
concibe como un proceso de transformacin de
estado reejado en las variables a lo largo del
Eempo

1-4

E 0
S1
E 1
S2

Ejecucin secuencial
El programa se ejecuta de principio a n
respetando el orden correlaEvo que cada
instruccin guarda con la instruccin
anterior y siguiente

E 2
S3
E 3
S4

@javiervelezreye

Programacin Asncrona en Node JS


Introduccin
II. Programacin Asncrona

La programacin asncrona establece la posibilidad de hacer que algunas operaciones


devuelvan el control al programa llamante antes de que hayan terminado mientras siguen
operando en segundo plano. Esto agiliza el proceso de ejecucin y en general permite
aumentar la escalabilidad pero complica el razonamiento sobre el programa.

Operaciones no bloqueantes
Ahora algunas operaciones son no bloqueantes
ya que devuelven el control al programa
llamante antes de su terminacin mientras
siguen ejecutando en segundo plano

Imposible razonar sobre el estado


La falta de secuencialidad estricta en la
ejecucin del programa hace diOcil determinar
el estado al comienzo de cada operacin

Ejecucin no secuencial

E 0
S1
E 1
E 2
S3

S2

Ya n o se manEene el o rden
secuencial puesto la ejecucin de la
instruccin que sigue a un operacin
no bloqueante se adelanta antes de
que dicha no bloqueante haya
nalizado

E 3
S4

Aumento de la escalabilidad
La asincrona permite que los
siguientes procesos en espera
adelanten su ejecucin

1-5

@javiervelezreye

Programacin Asncrona en Node JS


Introduccin
II. Programacin Asncrona

Lo Bueno

Lo Malo

La programacin asncrona resulta ventajosa ya


que aumenta el throughput soportado. Esta
ventaja le est haciendo coger mucha traccin
dada la demanda de sistemas de alta
escalabilidad que se requieren en Internet.

El principal problema de la programacin


asncrona se reere a cmo dar con2nuidad a
las operaciones no bloqueantes del algoritmo
una vez que stas han terminado su ejecucin.

Cola de Procesos
entrantes

S1

Startup
S3

S2

S4

Shutdown

1-6

cmo conEnuamos? cmo


recuperamos el estado en
este punto? cmo obtengo
los resultados?

@javiervelezreye

Programacin Asncrona en Node JS


Introduccin
III. Modelos de Programacin Asncrona

Para dar respuesta al problema anterior cmo dar tratamiento de con2nuidad al resultado
de las operaciones no bloqueantes una vez que stas han terminado se han establecido
diferentes modelos de programacin asncrona. Las bondades de dichos modelos se valoran en
trminos de cunto permiten aproximar la programacin asncrona a un esquema lo ms
parecido al secuencial.

I. Modelo de Paso de ConQnuaciones

II. Modelo de Eventos

Es el modelo de asincrona denido dentro de


Node JS. Cada funcin recibe informacin
acerca de cmo debe tratar el resultado de
xito o error de cada operacin. Requiere
orden superior

Se u2liza una arquitectura dirigida por eventos


que permite a las operaciones no bloqueantes
informar de su terminacin mediantes seales
de xito o fracaso. Requiere correlacin para
sincronizar

III. Modelo de Promesas

IV. Modelo de Generadores

Se razona con los valores de retorno de las


operaciones no bloqueantes de manera
independiente del momento del 2empo en que
dichos valores de xito o fallo se obtengan

Se u2lizan generadores para devolver


temporalmente el control al programa llamante
y retornar en un momento posterior a la ru2na
restaurando el estado en el punto que se
abandon su ejecucin

1-7

@javiervelezreye

Programacin Asncrona en Node JS


Introduccin
Sequen,al.js

IV. Un ejemplo

Para entender compara2vamente cada uno de estos cuatro modelos u2lizaremos a lo largo de
esta charla un sencillo ejemplo que expone los 3 2pos de problemas caracters2cos
relacionados con el control de ujo dentro de programas asncronos.
Dada una coleccin de cheros, leer su
contenido y contabilizar el nmero total de
ocurrencias de cada carcter contenido
dentro de los mismos

1. Leer cada chero en paralelo
2. Contabilizar su nmero de ocurrencias
3. Sumar los resultados

Cmo paralelizar?
init

read

count

Cmo secuenciar?
add

Cmo sincronizar?

1-8

@javiervelezreye

Node JS como
Lenguaje Asncrono

La Asincrona de Node JS
Principios Arquitectnicos de Node JS
Arquitectura de Node JS

Node JS como Lenguaje Asncrono

2
Javier.veler.reyes@gmail.com

Programacin Asncrona en Node JS

Javier Vlez Reyes


@javiervelezreye

Programacin Asncrona en Node JS


Node JS como Lenguaje Asncrono
I. La Asincrona de Node JS

Parece natural pensar que la programacin asncrona exige de un contexto mul2-hilo ya que el
carcter no bloqueante se consigue por medio de una suerte de ejecucin simultanea que
transcurre en un segundo plano del ujo principal del programa. Sin embargo, esto no implica
necesariamente un contexto de ejecucin concurrente ya que las operaciones no bloqueantes
pueden ejecutarse de forma aislada.

Node JS is a pladorm built on Chrome's JavaScript


run2me for easily building fast, scalable network
applica2ons. Node JS uses an event-driven, non-
blocking I/O model that makes it lightweight and
ecient, perfect for data-intensive real-2me
applica2ons that run across distributed devices.
Modelo no bloqueante de E/S
Node JS es un lenguaje single-thread pero que
aplica mul2-threading en los procesos de
entrada salida y es ah donde se aplica el
carcter no bloqueante

1-10

Arquitectura dirigida por eventos


Node JS u2liza alterna2vamente, como
veremos, el modelo de paso de con2nuaciones
y el de eventos si bien su arquitectura general
est dirigida por un loop general de eventos

@javiervelezreye

Programacin Asncrona en Node JS


Node JS como Lenguaje Asncrono
II. Principios Arquitectnicos de Node JS

A pesar de que recientemente Node JS est recibiendo, especialmente desde ciertas


comunidades compe2doras, fuertes cr2cas rela2vas a su aprovechamiento de los ciclos de
cmputo por tratarse de un entorno single-thread, su losoga se basa en tres fuertes
principios arquitectnicos.

1. La E/S es lo que ms coste implica


Esta experimentalmente comprobado que
procesamiento de las operaciones de E/S es el
que mayor coste implica dentro de las
arquitecturas Hw.

1-11

2. Dedicar un hilo por solicitud es caso


Dedicar un hilo para enhebrar el procesamiento
de cada solicitud entrante, como hacen otras
arquitecturas servidoras (Apache) resulta
demasiado caro en memoria

3. Todo en paralelo menos tu cdigo


C o m o c o n s e c u e n c i a e l e s q u e m a d e
comportamiento de Node JS se puede resumir
en aquellas partes del proceso de la pe2cin
que merezca la pena paralelizar (E/S) se
ejecutarn de forma no bloqueante mientras
que el resto ejecuta en un esquema single-
thread

@javiervelezreye

Programacin Asncrona en Node JS


Node JS como Lenguaje Asncrono
III. Arquitectura de Node JS
1. Nueva Solicitud
Llegan las solicitudes a
Node JS desde el exterior

5. Procesar resultados
Se ejecuta la lgica de
conEnuidad que procesa
los resultados

1-12

2. GesQn
Un nico hilo se encarga de
gesEonar las solicitudes
entrantes

3. Ejecucin no bloquante
Las operaciones de E/S se
procesan en paralelo en
modo no bloqueante

Node JS is a pladorm built on Chrome's JavaScript


run2me for easily building fast, scalable network
applica2ons. Node JS uses an event-driven, non-blocking
I/O model that makes it lightweight and ecient, perfect
for data-intensive real-2me applica2ons that run across
distributed devices.

Todo Se Ejecuta en Paralelo


menos tu Cdigo

4. Finaliza la operacin
C u a n d o l a o p e r a c i n
termina vuelve al loop

@javiervelezreye

Modelo de Paso de
Con,nuidades

Qu es una Con2nuacin
Control de Flujo Mediante Con2nuaciones
Ejemplo
Libreras
Conclusiones

Modelo de Paso de Con,nuidades

3
Javier.veler.reyes@gmail.com

Programacin Asncrona en Node JS

Javier Vlez Reyes


@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Paso de Con2nuidades
I. Qu es Una ConQnuacin

El modelo na2vo que u2liza Node JS en sus APIs para dar soporte a la programacin asncrona
es el de paso de con2nuaciones. Cada operacin no bloqueante recibe una funcin como
l2mo parmetro que incluye la lgica de con2nuacin que debe ser invocada tras la
nalizacin de la misma tanto para procesar los resultados en caso de xito como para tratar
los fallos en caso de error.
Proveedor

Paso de ConQnuacin

function div(a, b, callback) {


if (b === 0) callback (Error (...))
else {
var result = a / b;
callback (null, result);
}
}

La funcin de conEnuacin permite indicar


a la operacin bloqueante como debe
proceder despus de nalizada la
operacin

Cliente
div (8, 2, function (error, data) {
if (error) console.error (error);
else console.log (data);
});

1-14

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Paso de Con2nuidades
II. Control de Flujo Mediante ConQnuaciones

A. Secuenciamiento

La manera de proceder dentro de este modelo para establecer ujos de ejecucin secuenciales
exige ir encadenando cada funcin subsiguiente como con2nuacin de la anterior donde se
procesarn los resultados tanto en caso de xito como de fracaso. Esto conduce a una
diagonalizacin del cdigo que se ha dado en llamar pirmide del inerno (callback hell), por su
falta de manejabilidad prc2ca en cuanto crece mnimamente el nmero de encadenamientos
secuenciales.
mul(2, 3, function (error, data) {
if (error) console.error (error);
else div(data, 4, function (error, data) {
if (error) console.error (error);
else add(data, 5, function (error, data) {
...
});
});
});

mul (2, 3)
div (3, 4)

add (4, 5)

2 * 3 / 4 + 5

1-15

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Paso de Con2nuidades
II. Control de Flujo Mediante ConQnuaciones

B. Paralelizacin

La paralelizacin ejecucin asncrona de las operaciones no bloqueantes es inmediata ya


que su mera invocacin ejecuta en segundo plano por denicin. Para conver2r en no
bloqueantes las operaciones bloqueantes, se requiere un pequeo proceso de encapsulacin
funcional que lance la operacin en segundo plano.
add(2, 3, function (error, data) {...});
sub(3, 4, function (error, data) {...});
add (2, 3)

sub(3, 4)

function doAsync (fn, callback, self) {


return function () {
var allParams = [].slice.call(arguments);
var params
= allParams.slice (0, allParams.length - 1);
var callback = allParams[allParams.length - 1];
setTimeout (function () {
var results = fn.apply (self, params)
callback (null, results);
}, 0);
};
}

1-16

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Paso de Con2nuidades
II. Control de Flujo Mediante ConQnuaciones

C. Sincronizacin

La sincronizacin de funciones de con2nuacin requiere encadenar al nal de cada secuencia


paralela una funcin de terminacin que aplique cierta lgica slo una vez que se compruebe
que todas los ramas paralelas han terminado. Para implementar esta comprobacin se u2lizan
esquemas basados en contadores.
function doParallel(fns, endCallback, params) {
var pending = fns.length;
var callback = function (error, data) {
<<processing data && error>>
pending --;
if (pending === 0) {
endCallback();
}
}
for (var index = 0; index <fns.length; index ++) {
fns[index].apply (this, params[index], callback);
}
}

add (2, 3)

sub (4, 5)

console

doParallel ([add, sub], function (error, data) {


console.log (data)
}, [[2,3],[4,5]]);

1-17

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Paso de Con2nuidades
Con,nua,ons.js

III. Ejemplo

Dada una coleccin de cheros, leer su


contenido y contabilizar el nmero total de
ocurrencias de cada carcter contenido
dentro de los mismos

1. Leer cada chero en paralelo
2. Contabilizar su nmero de ocurrencias
3. Sumar los resultados

Paralelizacin
Un bucle permite lanzar en
ejecucin todos los pares no
bloqueantes de leer-contar de
forma no bloqueante
init

read

Secuenciamiento
Cada par leer-contar se encadena
a travs del paso de funciones de
conEnuacin

Sincronizacin

count

add

Para sincronizar cada rama paralela recibe una


lEma conEnuacin que ejecuta lgica de
terminacin una vez que se ha asegurado que todas
las ramas han terminado

1-18

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Paso de Con2nuidades
IV. Libreras

Existen numerosas libreras que pueden ayudarnos a hacer la vida ms fcil cuando trabajamos
con un modelo de programacin asncrona basado en con2nuaciones. Algunas de ellas no
estn estrictamente relacionadas con la programacin asncrona sino con el paradigma
funcional lo cual se debe a que los mecanismos de inyeccin de con2nuaciones son en esencia
ar2cios funcionales.

Join

Async
Async es tal vez la librera ms conocida y
ampliamente uElizada para la programacin
asncrona basada en conEnuaciones. Ofrece
mtodos de control de ujo variados para
funciones no bloqueantes

Join es una implementacin del mtodo de


sincronizacin que hemos comentado
anteriormente y resulta similar al que puede
encontrarse en otros lenguajes como C que
opera con threads. Tambin puede usarse en
promesas aunque su uso resulta menos
relevante

Fn.js
Fn.js es una excelente librera que implementa
disEntos mtodos de gesEn funcional. Su
aplicabilidad prcEca en este contexto est
relacionada con las capacidades que expone
para generar funciones no bloqueantes y
aplicar curricacin

1-19

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Paso de Con2nuidades
V. Conclusiones

Lo Bueno

Lo Malo

La programacin asncrona basada en


con2nuidades puede ser una buena opcin para
situaciones en que la lgica de control de ujo
es muy sencilla. Tal suele ser el caso de
programas en Node JS que permiten denir una
respuesta no bloqueante a pe2ciones entrantes

No obstante, cuando la lgica de control resulta


mnimamente elaborada el proceso de
razonamiento sobre el programa se complica lo
cual redunda en un cdigo con lgica funcional
distribuida y digcil de leer, entender y
mantener.

Sencillo para esquemas


solicitud / respuesta
Alineado con los
esquemas de
programacin funcional
Fcil de entender como
mecanismo conceptual

1-20

Complejidad en la denicin de
una lgica de control de ujo
elaborada
Di`cil establecer
mecanismos de
sincronizacin

La lgica de control
queda distribuida entre
cada rama no
bloqueante
Di`cil de seguir, leer y
mantener a medida que
crece el cdigo
@javiervelezreye

Modelo de
Eventos

Qu es una Arquitectura Dirigida por Eventos


Control de Flujo Mediante Eventos
Ejemplo
Libreras
Conclusiones

Modelo de Eventos

4
Javier.veler.reyes@gmail.com

Programacin Asncrona en Node JS

Javier Vlez Reyes


@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Eventos
I. Qu es Una Arquitectura dirigida por Eventos

Un evento es la sealizacin de un acontecimiento relevante dentro del ecosistema de


negocio. Anatmicamente estn formados, kpicamente, por un 2po, una marca de 2empo y
un conjunto de datos que caracteriza el contexto en el que se produjo el evento. Las
arquitecturas de eventos (EDA) proporcionan un mecanismo de comunicacin entre clientes y
proveedores en relacin 1:N y con desacoplamiento nominal. Una de sus muchas aplicaciones
es en los problemas de procesamiento asncrono de datos.
Proveedor

Cliente
registro

evento
noEcacin

reaccin

Arquitectura de Eventos
Se produce una comunicacin desacoplada
entre proveedores y clientes a travs de un
mecanismo de registro/noEcaciones. Ntese
que en este esquema las echas no indican
invocaciones sino comunicacin indirecta

1-22

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Eventos
I. Qu es Una Arquitectura dirigida por Eventos

Arquitectura Centralizada

En las arquitecturas centralizadas dirigidas por eventos existe un mediador central bus de
comunicaciones que se encarga de hacer efec2vo el proceso de registro de los clientes
escuchadores y de lanzar las no2caciones bajo demanda de los proveedores a los mismos.
Este mecanismo permite una cardinalidad N:N. Este esquema se conoce bajo el nombre de
patrn PUB/SUB.
Bus

Proveedor
evento

var bus = Bus.create ();


bus.send(app.module.event, data);

1-23

noEcacin

Cliente

manejador

var bus = Bus.create ();


bus.receive(app.module.event,
function (data) {
...
});
bus.refuse(app.module.event);
bus.refuseAll();

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Eventos
I. Qu es Una Arquitectura dirigida por Eventos

Arquitectura Distribuida

En las arquitecturas distribuidas dirigidas por eventos cada proveedores es responsable de


ges2onar la suscripcin de sus clientes y de enviar las no2caciones cuando se produce un
evento. El mecanismo de comunicacin tambin es desacoplado nominalmente pero la
cardinalidad kpicamente es de 1:N entre el proveedor y los clientes. Este esquema se
corresponde con el patrn observador-observable o event emibers en jerga Node JS.
Manejadores
registrados

Proveedor

Cliente
registro

noEcacin

var events = require(events);


var emitter = new events.EventEmitter();
emitter.emit(app.module.event, data);

1-24

emmiter.on(app.module.event,
function h(data) {
...
});
bus.removeListener(app.module.event, h);
bus.removeAllListeners(app.module.event);

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Eventos
II. Control de Flujo Mediante Eventos

A. Secuenciamiento

El secuenciamiento dentro de este modelo se consigue a travs del encadenamiento de


escuchadores. Los resultados de las operaciones van cayendo en cascada desde la primera
hasta la l2ma acumulndose parcialmente hasta llegar a un resultado nal que es recogido y
procesado por el cliente.
var addEmitter = new events.EventEmitter();
var mulEmitter = new events.EventEmitter();
function add(x, y) {
addEmitter.emit(result, x+y);
}
function mul(z) {
addEmitter.on(result, function (data){
mulEmitter.emit(result, data * z);
});
}

r = add (x, y)
mul (r, z)
(2 + 3) * 5

mul(5);
mulEmitter.on(result, function (data){
console.log(data);
});
add (2,3);

1-25

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Eventos
II. Control de Flujo Mediante Eventos

B. Paralelizacin

En tanto que las arquitecturas dirigidas por eventos establecen un marcado desacoplamiento
entre los agentes par2cipantes, lo nico que es necesario hacer para paralelizar varias
operaciones es hacer que cada una opere de manera independiente y lance eventos cuando
genere resultados.
var addEmitter = new events.EventEmitter();
var subEmitter = new events.EventEmitter();
function add(data) {
addEmitter.emit(result, x+y);
}
function sub(x, y) {
subEmitter.emit(result, x-y);
}

add (2, 3)

sub(3, 4)

var emitter = new events.EventEmitter();


function add(x, y) {
emitter.emit(add, x+y);
}
function sub(x, y) {
emitter.emit(sub, x-y);
}

1-26

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Eventos
II. Control de Flujo Mediante Eventos

C. Sincronizacin

Finalmente, la sincronizacin requiere un proceso de escucha de todas las fuentes emisoras de


eventos que operan sobre el nal de cada rama paralela. Debe incluirse en las funciones
manejadoras lgica de tratamiento que emita nuevos eventos ms generales con datos
resultantes el proceso de sincronizacin. A esto se le llama correlacin de eventos.
var addEmitter = new events.EventEmitter();
var subEmitter = new events.EventEmitter();
...
function mul() {
var r;
function h(data) {
if (r) {console.log (r * data)}
else r = data;
};
addEmitter.on (result, h);
subEmitter.on (result, h);
}
mul ();

r1=add (2, 3) r2=sub (4, 5)

mul (r1,r2)

Correlacin de Eventos
Existe una gran coleccin de patrones de
diseo propios de las arquitecturas de
correlacin entre los que se cuentan,
transformaciones, agregados, ltros o
abstracciones temporales

1-27

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Eventos
Events.js

III. Ejemplo

Dada una coleccin de cheros, leer su


contenido y contabilizar el nmero total de
ocurrencias de cada carcter contenido
dentro de los mismos

1. Leer cada chero en paralelo
2. Contabilizar su nmero de ocurrencias
3. Sumar los resultados

Paralelizacin
Se lanzan a ejecucin de forma iteraEva
todas las ramas secuenciales para que
operen en paralelo emiEendo eventos
init

read

Secuenciamiento
La operacin read emite eventos de datos ledos del
chero en bloques de 1024 bytes. La operacin count
escucha esos eventos y genera resultados
acumulaEvamente que emite como evento slo
cuando read enva la seal de n de chero

Sincronizacin

count

add

La operacin add sincroniza todas las operaciones


count. Va calculando los totales acumulaEvamente y
slo emite un evento cuando determina que se han
ledo todos los resultados

1-28

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Eventos
IV. Libreras

Dado que existen dos es2los arquitectnicos que operan dentro del modelo de las
arquitecturas dirigidas por eventos el centralizado y el distribuido parece razonable dividir
las contribuciones de libreras que existen entre esas dos categoras.

Arquitecturas Distribuidas
Events
Events es un mdulo estndar de Node JS
uElizado para trabajar con eventos. Dispone de
un constructor de emisor de eventos con todos
los mtodos necesarios para el registro,
desregistro y propagacin de eventos.

Arquitecturas Centralizadas
Postal
Postal es un bus de comunicaciones que
implementa el patrn PUB-SUB tanto para cliente
como para servidor. Usa expresiones regulares
sobre el Epo de eventos para gesEonar familias y
goza de buena comunidad

UQl
Algunos autores uElizan el mtodo inherits de la
librera estndar uEl con el n de explotar las
capacidades de la librera events por herencia en
lugar de por delegacin

1-29

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Eventos
V. Conclusiones

Lo Bueno

Lo Malo

El modelo dirigido por eventos ofrece grandes


posibilidades y da respuesta a un abanico nuevo
de problemas que resultan concomitantes con
la programacin reac2va y las soluciones de
correlacin de eventos.

Aunque este modelo es altamente prometedor


y supone grandes ventajas con respecto al de
paso de con2nuaciones, no deja de tener
detractores que consideran el uso de promesas
un artefacto demasiado ar2cial e incomodo de
tratar.

Desacoplamiento
nominal
Esquemas de
comunicacin 1:N o N:M
Fcil extensibilidad del sistema
reacQvo por medio de la adicin
de nuevos manejadores
Razonamos localmente en
problemas desacoplados
1-30

Los procesos de coordinacin


resultan complicados
La lgica de
secuenciamiento queda
diluida entre los
Resulta ms invasivo
manejadores
que otras soluciones
Cdigo di`cil de seguir, mantener
y depurar a medida que crece el
tamao del problema
@javiervelezreye

Modelo de
Promesas

Qu es una Promesa
Control de Flujo Mediante Promesas
Ejemplo
Libreras
Conclusiones

Modelo de Promesas

5
Javier.veler.reyes@gmail.com

Programacin Asncrona en Node JS

Javier Vlez Reyes


@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Promesas
I. Qu es Una Promesa

Una promesa es una abstraccin computacional que representa un compromiso por parte de
la operacin no bloqueante invocada de entregar una respuesta al programa llamante cuando
se obtenga un resultado tras su nalizacin. La promesa es un objeto que expone dos mtodos
inyectores then y fail para incluir la lgica de tratamiento en caso de xito o fracaso.
var promise = div (a, b);
promise.then (function (data) {
console.log (data)
}).fail (function (error) {
console.error (error)
});

Inyeccin de manejadores
La promesa incluye dos funciones, then y fail,
que permiten indicar cmo tratar los resultados
o manejar los errores una vez que la operacin
no bloqueante ha terminado

Comunicacin basada en promesas


Se recupera el control sobre el ujo del
programa. Los proveedores vuelven a devolver
(promesas de) valores y los clientes uElizar esas
(promesas de) valor en una expresin

1-32

function div (x, y) {


var result = ...
return <<toPromise (result)>>;
}

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Promesas
I. Qu es Una Promesa

Ciclo de vida de una promesa


Las promesas responden a un sencillo ciclo de vida que es necesario conocer para operar con
ellas convenientemente. El valor esencial de una promesa reside en 2 principios. Primero que
la lgica de tratamiento en caso de xito o fracaso slo se ejecuta una vez. Y segundo que se
garan2za la ejecucin de la lgica de xito o fracaso aunque la promesa se resuelva antes de
haber inyectado sus manejadores. La promesa espera, si es necesario a disponer de sus
manejadores.
Sebled

value

Fullled

Pending

fail (error)

error
Se espera la nalizacin
del mtodo async
El mtodo async ha
terminado con una
respuesta

1-33

then (value)

Resolved

Rejected

El manejador an
no se ha ejecutado,
est inyectado o no

Se ha ejecutado la
funcin manejadora
de xito o de fracaso

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Promesas
I. Qu es Una Promesa

Construccin de Promesas
Existen diversas formas de obtener promesas que pueden iden2carse como patrones de
construccin que aparecen recurrentemente al u2lizar este modelo. A con2nuacin
comentamos los ms relevantes con ejemplos en la librera Q.
Obtencin directa

Invocacin funcional

var promise = getPromise ();

return Q.fcall (function () {


return value;
});

Resolucin directa
var promise = Q.resolve (value);

Rechazo directo
var promise = Q.reject(error);

Factora de diferidos
var deferred = Q.defer();
if (error) deferred.reject (error);
if (data) deferred.resolve (data);
return deferred.promise;

Denodicacin
var f = Q.denodeify(fs.readFile);
var f = Q.nfbind (fs.readFile);
Q.nfcall (fs.readFile (...));

1-34

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Promesas
II. Control de Flujo Mediante Promesas

A. Secuenciamiento

La lgica de control secuencial puede obtenerse mediante el encadenamiento the sucesivas


invocaciones al mtodo de inyeccin then. Este encadenamiento provoca un comportamiento
secuencial puesto que cada funcin then genera, al retornar, una promesa que encapsula el
valor devuelto (a menos que ste sea ya una promesa) lo que obliga a mantener el orden.
Q.resolve (2)
.then (function (value)
return value - 1;
})
.then (function (value)
return value - 1;
})
.then (function (value)
if (value===0) throw
return (8 / value);
})
.then (function (value)
return value + 1;
})
.fail (function (error)
console.log (error);
});

1-35

2
{
1
{
{
Error ();

{
{

error

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Promesas
II. Control de Flujo Mediante Promesas

B. Paralelizacin

Al igual que ocurra en el modelo de paso de con2nuidades, la paralelizacin se consigue por


invocacin directa de las operaciones, ya que stas 2enen un comportamiento no bloqueante.
En este modelo sin embargo la programacin resulta ms natural ya que cada operacin
devuelve un valor de retorno instantneamente en forma de promesa.
var r1 = add(2, 3);
var r2 = sub(3, 4);

var r1 = Q.fcall (add, 2, 3);


var r2 = Q.fcall (sub, 3, 4);

function doParallel(fns, params) {


var promises = [];
for (var index = 0; index < fns.length; index ++) {
var p = Q.fapply (fns[index], params[index]);
promises.push (p);
}
return promises;
}

add (2, 3)

sub(3, 4)

var promises = doParallel ([add, sub], [[2,3],[4,5]]);

1-36

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Promesas
II. Control de Flujo Mediante Promesas

C. Sincronizacin

Dado que disponemos de los resultados potenciales en forma de promesas es fcil ar2cular
sobre ellos pol2cas de sincronizacin. El mtodo all genera una promesa que toma una array
de promesas y se resuelve a un array de valores cuando todas las promesas se han resuelto. Si
hay fallo se devuelve el de la primera promesa del array en fallo. allSebled por su parte
resuelve cuando todas las promesas estan en senled. Finalmente, spread es la versin en array
del mtodo then.
var promises = doParallel ([add, sub], [[2,3],[4,5]]);
Q.all (promises).then (function (values) {
console.log (values);
});
var promises = doParallel ([mul, div], [[2,3],[4,0]]);
Q.allSettled (promises).spread (function (vMul, vDiv) {
if (vMul.state === "fulfilled") console.log (vMul.value);
if (vDiv.state === "fulfilled") console.log (vDiv.value);
});

1-37

add (2, 3)

sub (4, 5)

console

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Promesas
Promises.js

III. Ejemplo

Dada una coleccin de cheros, leer su


contenido y contabilizar el nmero total de
ocurrencias de cada carcter contenido
dentro de los mismos

1. Leer cada chero en paralelo
2. Contabilizar su nmero de ocurrencias
3. Sumar los resultados

Paralelizacin
Se lanzan a ejecucin de forma iteraEva
todas las ramas paralelas y se construye
un array de promesas para su posterior
sincronizacin.
init

read

Secuenciamiento
El secuenciamiento consiste meramente
en encadenar las funciones de lectura y
conteo con dos mtodos then.

Sincronizacin

count

add

Se recogen las promesas que resultan de cada rama


secuencial en un array para poderlas sincronizar
haciendo uso del mtodo all.

1-38

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Promesas
IV. Libreras

Existen varias libreras que implementan el


modelo de promesas. Tal vez la de mayor
comunidad es Q, aunque otras como When
o RSVP, tambin gozan de bastante
traccin. En aras a disponer de un marco
compara2vo de referencia se ha denido el
estndar Promises A+ que rige todas todas
las libreras con objetos then-able.

1-39

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Promesas
V. Conclusiones

Lo Bueno

Lo Malo

Hemos recuperado en gran parte el control de


ujo del programa de manera que el esquema
de desarrollo de aplicaciones asncronas
basadas en promesas se parece algo ms al
es2lo secuencial manteniendo su carcter no
bloqueante.

Aunque este modelo es altamente prometedor


y supone grandes ventajas con respecto al de
paso de con2nuaciones, no deja de tener
detractores que consideran el uso de promesas
un artefacto demasiado ar2cial e incomodo de
tratar.

Recuperamos el return y
la asignacin
APIs ms limpias sin
mtodos de callback
(callback en cliente)
Estructura del programa
ms similar a la
programacin secuencial
Razonamos con promesas
como valores de futuro
1-40

No deja de ser necesario


inyectar funciones manejadoras
de xito y error
Resulta di`cil depurar
hasta que las promesas
no se han resuelto
Es imprescindible hacer
uso de libreras de
terceros para gesQonar
las promesas

Resulta ms invasivo
generar APIs que
consuman y generen
promesas

@javiervelezreye

Modelo de
Generadores

Qu es un Generador
Los Generadores como Modelo de Asincrona
Control de Flujo Mediante Generadores
Ejemplo
Libreras
Conclusiones

Modelo de Generadores

6
Javier.veler.reyes@gmail.com

Programacin Asncrona en Node JS

Javier Vlez Reyes


@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Generadores
Generators.b.js

I. Qu es Un Generador

Requiere
NodeJS > 0.11
Imagina un procedimiento que pudiera ser interrumpido en su ejecucin en cualquier punto
ag --harmony

antes de su terminacin para devolver el control al programa llamante y ms adelante ste


volver a cederle el control para que con2ne justo en el punto donde fue interrumpido y con el
estado que tena. Eso es un generador. Antes de ver su aplicacin en modelos de asincrona
veamos cmo funciona y cul puede ser su aplicabilidad prc2ca.

Next
Inicia o reanuda la ejecucin
hasta el siguiente next
var fib = fibonacci() {
for (var i=0; i<10; i++) {
var f = fib.next();
console.log(f.value);
}
}
console.log
console.log
console.log
console.log
console.log

1-42

{ value: n,
done: false }

(fib.next().value);
(fib.next().value);
(fib.next(true).value);
(fib.next().value);
(fib.next().value);

function* fibonacci () {
var a = 1;
var b = 0;
var aux;
while (true){
aux = a + b;
a
= b;
b
= aux;
var reset = yield b;
if (reset){
a = 1;
b = 0;
}
}
}

Yield
Suspende la ejecucin
y devuelve b

Reset
ObEene como retorno
el argumento de next

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Generadores
II. Los Generadores como Modelo de Asincrona
Qu es Una Clausura?
JS es un lenguaje de orden superior lo que implica que trata a las funciones como cualquier
otro 2po de dato. Pueden asignarse a variables, pasarse como parmetros o devolverse como
resultado. Lo bueno de esto l2mo es que una funcin que es devuelta como resultado de
invocar a otra funcin man2ene el contexto de variables denido dentro de esta l2ma para su
ejecucin. Veamos un ejemplo:
function Logger(cls) {
var pre = Logger;
var post = ...;
return function (message) {
console.log ('%s[%s] - [%s]%s',
pre, cls, message, post);
}
}
var log = Logger (Generators);
log(starting);
log(1234);
log(end);

1-43

clausura
pre

post

cls

function (message) {...}

Clausura
Al devolver una funcin hacia fuera del
mbito de denicin se manEene el contexto
de variables y parmetros que dicha funcin
Eene dentro, de forma trasparente. A ese
contexto se le llama clausura

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Generadores
II. Los Generadores como Modelo de Asincrona
Qu es Evaluacin Parcial de una Funcin?
En muchas ocasiones resulta conveniente conver2r una funcin de n parmetros en otra que
resuelve el primer parmetro y devuelve como resultado otra funcin con n-1 parmetros. A
esto se le llama evaluacin parcial de una funcin. Cuando la evaluacin parcial se repite para
cada parmetro de la funcin el proceso se llama curricacin.
function add(a, b) {
return a + b;
}
var r = add(3, 2);

Evaluacin total
En la evaluacin total el cliente
debe esperar hasta obtener todos
los parmetros actuales (3 y 2)
para poder invocar a la funcin

1-44

function add(a) {
return function (b) {
return a + b;
}
}
var r1 = add(3)(2);
var inc = add(1);
var r2 = inc(5);

Evaluacin parcial
En la evaluacin parcial cada parmetro (por orden)
puede ser resuelto de manera independiente en sucesivas
evaluaciones. Esto, como veremos, nos da la oportunidad
de conseguir que sean disEntos clientes los que realicen
cada evaluacin parcial

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Generadores
II. Los Generadores como Modelo de Asincrona
Qu es un Thunk?
En trminos generales un Thunk es una abstraccin computacional que sirve de vehculo para
comunicar informacin entre dos frameworks diferentes. En nuestro caso queremos pasar de
un modelo de invocacin basado en con2nuaciones en otro que las oculte. Haciendo uso de los
dos conceptos anteriores clausuras y evaluacin parcial proponemos construir el siguiente
thunk.
function add(a, b, callback){
callback (null, x + y);
}
add(3, 2, function(error, data){
console.log (data);
});

Thunk
Nuestros thunks devuelven funciones que esperan
manejadores como parmetros. De esta manera
ocultamos el manejador en la primera evaluacin parcial:
add (2,3);

1-45

function add(a, b) {
return function (callback) {
callback (null, x + y);
}
}
var r = add(3, 2);
r(function (error, data) {
console.log (data);
});

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Generadores
II. Los Generadores como Modelo de Asincrona
Generadores y Thunks
Podemos construir un framework sobre el que escribir generadores que devuelvan thunks (con
yield) lo que simplica el cdigo cliente. El framework por su parte va secuenciando el cdigo
del generador (con next) y se interpone para resolver de forma transparente la segunda
evaluacin parcial que corresponde con la funcin de callback. Su labor consiste en extraer los
datos del callback y retornarlos al generador para que ste los obtenga como una variable local

Generators.co.js
Requiere
NodeJS > 0.11
ag --harmony

Cliente

Framework

co (function* (){
var r1 = yield add (2,3);
var r2 = yield sub (3,4);
console.log (r1, r2);
})();

var co = function (codeGn) {


var code = codeGn ();
function step(thunk) {
if (thunk.done) return thunk.value;
else {
thunk.value (function (error, data){
step(code.next (data));
});
}
}
return function () {
step(code.next ());
};
};

1-46

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Generadores
II. Control de Flujo Mediante Generadores

A. Secuenciamiento

De lo que hemos visto, el uso de yield dentro de un generador evaluado por nuestro
framework asncrono permite a ste interponerse para capturar la funcin de callback y
resolver un thunk en su valor equivalente. De ello se deduce que cada vez que queramos
secuenciar operaciones slo tenemos que interponer yield antes de la operacin.
co(function* (){
var r1 = yield mul(2,3);
var r2 = yield div(3,4);
var r3 = yield add(4,5);

mul (2, 3)
div (3, 4)

console.log (r1, r2, r3);


})();
add (4, 5)

Yield en secuencia
Cada yield puede leerse como un paso dentro de una
secuencia de operaciones. Cada operacin no bloqueante
(mul, div y add) devuelve un thunk que el framework, co,
recoge para resolver a un valor y devolverlo al contexto
del generador como una variable local (r1, r2 y r3)

1-47

2 * 3 / 4 + 5

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Generadores
II. Control de Flujo Mediante Generadores

B. Paralelizacin & C. Sincronizacin

Razonablemente todas aquellas operaciones no bloqueantes que no sean intercedidas por el


framework a travs de la clusula yield darn lugar a esquemas de ejecucin paralelos. Es una
prc2ca comn agrupar estas invocaciones en colecciones (arrays u objetos) para
posteriormente hacer la resolucin de thunks a valores.
co(function* (){
var r1 = add(2,3);
var r2 = sub(3,4);
var r = yield [r1, r2];
add (2, 3)

console.log (r);
})();

Yield de Array
Yield aplicado a un array se evala como el
array de los yields. Yield aplicado a un objeto se
evala como el yield aplicado a cada propiedad
del objeto. De esta forma, este yield convierte el
array de thunks en un array de valores

1-48

sub(3, 4)

Array de thunks
Cada operacin no bloqueante aqu es evaluada sin la
clausula yield con lo que lo que se obEene en r1 y r2 son
dos thunks ejecutados en paralelo

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Generadores
Generators.js

III. Ejemplo

Dada una coleccin de cheros, leer su


contenido y contabilizar el nmero total de
ocurrencias de cada carcter contenido
dentro de los mismos

1. Leer cada chero en paralelo
2. Contabilizar su nmero de ocurrencias
3. Sumar los resultados

Requiere
NodeJS > 0.11
ag --harmony

Paralelizacin
Mediante un bucle, se construye un
array de generadores para cada rama
paralela
init

read

Secuenciamiento
Se construye un generador capaz de
secuenciar las dos operaciones read y
count que conforman cada rama
paralela

Sincronizacin

count

add

Se hace un yield de los resultados para sincronizar y


se invoca a add para obtener los totales, que se
devuelven al cliente con otro yield ya que add
tambin es no bloqueante

1-49

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Generadores
IV. Libreras

Aunque existen varias libreras que dan soporte a esta idea ar2cular un framework de
soporte a la programacin asncrona basado en generadores la que goza de mayor
comunidad es co. En torno a ella se pueden encontrar una amplia coleccin de libreras
u2litarias vinculadas que conforman el ecosistema de co.

Co

Thunkify

El framework de programacin asncrona basado


en generadores con mayor aceptacin. Co no
slo es capaz de operar con Thunks como
abstraccin vehicular sino que tambin funciona
con promesas, funciones, generadores y
funciones generadoras.

Se trata de una simple funcin que convierte


a un thunk cualquier funcin denida de
acuerdo al modelo de paso de conEnuidades
estandarizado por Node JS.

Ecosistema Co*
Libreras especcas, adaptadores de APIs,
servidores, funciones uElitarias de control de
ujo Todo un ecosistema de herramientas
para programar dentro del framework co. Se
puede ver una relacin exhausEva en la wiki de
Co accesible desde github

1-50

@javiervelezreye

Programacin Asncrona en Node JS


Modelo de Generadores
V. Conclusiones

Lo Bueno

Lo Malo

La programacin asncrona basada en


generadores es, tal vez, la opcin que mejor ha
conseguido acercar la experiencia de desarrollo
a la programacin secuencial. A la fecha de esta
charla an es pronto para saber si ser
ampliamente aceptada por la comunidad o no.

El modelo de programacin asncrona basada


en generadores sigue teniendo inconvenientes
serios relacionados con la invasividad del
framework y el uso permanente de clausulas
yield para ar2cular el manejo del control ujo.

Esquema de
programacin similar al
secuencial
Transparencia en los
procesos de gesQn de
conQnuaciones
Curva de aprendizaje corta. Con
pocas reglas de pulgar se puede
razonar fcilmente en el
modelo
1-51

ArQcialidad del cdigo.


Perversin del uso de
los yields
Todo cdigo esta
siempre dentro de un
contexto Co

El cdigo est
plagado de yields

qu est haciendo Co
por debajo?

@javiervelezreye

Programacin Asncrona en Node JS


Preguntas

ConQnuaciones
Eventos

Promesas
Generadores

Javier Vlez Reyes

@javiervelezreye

Javier.velez.reyes@gmail.com
1-52

@javiervelezreye

Programacin Asncrona en
Node JS
Modelo de Paso de Con,nuaciones, Eventos,
Promesas y Generadores

Javier Vlez Reyes

@javiervelezreye

Javier.velez.reyes@gmail.com

Mayo 2014

Vous aimerez peut-être aussi