Академический Документы
Профессиональный Документы
Культура Документы
Asncrona
en
Node
JS
Modelo
de
Paso
de
Con,nuaciones,
Eventos,
Promesas
y
Generadores
@javiervelezreye
Javier.velez.reyes@gmail.com
Mayo 2014
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
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
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
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
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
Lo Malo
Cola
de
Procesos
entrantes
S1
Startup
S3
S2
S4
Shutdown
1-6
@javiervelezreye
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.
1-7
@javiervelezreye
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
2
Javier.veler.reyes@gmail.com
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.
1-10
@javiervelezreye
1-11
@javiervelezreye
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
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
3
Javier.veler.reyes@gmail.com
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
Cliente
div (8, 2, function (error, data) {
if (error) console.error (error);
else console.log (data);
});
1-14
@javiervelezreye
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
sub(3, 4)
1-16
@javiervelezreye
add (2, 3)
sub (4, 5)
console
1-17
@javiervelezreye
III.
Ejemplo
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
1-18
@javiervelezreye
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
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
Lo Malo
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
Modelo de Eventos
4
Javier.veler.reyes@gmail.com
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
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
1-23
noEcacin
Cliente
manejador
@javiervelezreye
Proveedor
Cliente
registro
noEcacin
1-24
emmiter.on(app.module.event,
function h(data) {
...
});
bus.removeListener(app.module.event, h);
bus.removeAllListeners(app.module.event);
@javiervelezreye
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
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)
1-26
@javiervelezreye
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
III.
Ejemplo
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
1-28
@javiervelezreye
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
Lo Malo
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
Modelo
de
Promesas
Qu
es
una
Promesa
Control
de
Flujo
Mediante
Promesas
Ejemplo
Libreras
Conclusiones
Modelo de Promesas
5
Javier.veler.reyes@gmail.com
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
1-32
@javiervelezreye
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
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
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
1-35
2
{
1
{
{
Error ();
{
{
error
@javiervelezreye
add (2, 3)
sub(3, 4)
1-36
@javiervelezreye
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
III.
Ejemplo
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
1-38
@javiervelezreye
1-39
@javiervelezreye
Lo Malo
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
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
I.
Qu
es
Un
Generador
Requiere
NodeJS
>
0.11
Imagina
un
procedimiento
que
pudiera
ser
interrumpido
en
su
ejecucin
en
cualquier
punto
ag
--harmony
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
1-43
clausura
pre
post
cls
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
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
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
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);
})();
1-46
@javiervelezreye
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)
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
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
III.
Ejemplo
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
1-49
@javiervelezreye
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
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
Lo Malo
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
El
cdigo
est
plagado
de
yields
qu
est
haciendo
Co
por
debajo?
@javiervelezreye
ConQnuaciones
Eventos
Promesas
Generadores
@javiervelezreye
Javier.velez.reyes@gmail.com
1-52
@javiervelezreye
Programacin
Asncrona
en
Node
JS
Modelo
de
Paso
de
Con,nuaciones,
Eventos,
Promesas
y
Generadores
@javiervelezreye
Javier.velez.reyes@gmail.com
Mayo 2014