Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Generadores en JavaScript

Sergio Arbeo
February 06, 2014

Generadores en JavaScript

Introducción a los generadores en JavaScript y a cómo nos permiten librarnos del callback hell.

Sergio Arbeo

February 06, 2014
Tweet

More Decks by Sergio Arbeo

Other Decks in Programming

Transcript

  1. CONOZCÁMONOS Sergio Arbeo Matemático, troll. Programador Ruby y CoffeeScript, entre

    otros. CodeCantor, ConectaLab Profesor de Rails avanzado en IronHack
  2. ¿Y VOSOTROS? Nivel Node: ¿Mande? Lo uso como herramienta externa

    Hago mis pinitos Trabajo a diario Odio el callback hell
  3. NODE HISTORIA Creado por Ryan Dahl en 2009 Basado en

    y Primer drama hace unos meses Liderada actualmente por Timothy J. Fontaine Google v8 libuv
  4. PRIMER EJERCICIO 1. Crea dos ficheros desde la terminal: a

    . t x t y b . t x t . 2. Crea un script en Node que lea los dos ficheros y los imprima en orden inverso al leído. 3. Os interesa el módulo f s y el método r e a d F i l e . 4. Cinco minutillos.
  5. PRIMER EJERCICIO: SOLUCIÓN v a r f s = r

    e q u i r e ( ' f s ' ) ; f s . r e a d F i l e ( " a . t x t " , " u t f 8 " , f u n c t i o n ( e r r , d a t a ) { i f ( e r r ) t h r o w e r r ; v a r f i r s t F i l e = d a t a ; f s . r e a d F i l e ( " b . t x t " , " u t f 8 " , f u n c t i o n ( e r r , d a t a ) { i f ( e r r ) t h r o w e r r ; v a r s e c o n d F i l e = d a t a ; c o n s o l e . l o g ( s e c o n d F i l e ) ; c o n s o l e . l o g ( f i r s t F i l e ) ; } ) ; } ) ;
  6. PRIMER EJERCICIO: COROLARIOS 1. Callbacks, el camino a la asincronicidad.

    2. No es fácilmente extrapolable a N ficheros.
  7. PRIMER EJERCICIO: GENERALIZADO Utiliza a s y n c para

    generalizar fácilmente el ejercicio anterior a tantos ficheros como haga falta. Recomendación del día: a s y n c . m a p .
  8. PRIMER EJERCICIO: GENERALIZADO v a r f s = r

    e q u i r e ( ' f s ' ) ; v a r a s y n c = r e q u i r e ( ' a s y n c ' ) ; v a r r f = f u n c t i o n ( f i l e n a m e , c b ) { r e t u r n f s . r e a d F i l e ( f i l e n a m e , " u t f 8 " , c b ) ; } ; a s y n c . m a p ( [ " a . t x t " , " b . t x t " , " c . t x t " ] , r f , f u n c t i o n ( e r r , d a t a ) { i f ( e r r ) { t h r o w e r r ; } f o r ( v a r i = d a t a . l e n g t h - 1 ; i > = 0 ; i - - ) { c o n s o l e . l o g ( d a t a [ i ] ) ; } } ) ;
  9. META Poder escribir código, manteniendo la asincronicidad, lo más parecido

    a: v a r f s = r e q u i r e ( ' f s ' ) v a r a F i l e = f s . r e a d F i l e ( ' a . t x t ' , ' u t f 8 ' ) ; v a r b F i l e = f s . r e a d F i l e ( ' b . t x t ' , ' u t f 8 ' ) ; c o n s o l e . l o g ( b F i l e ) ; c o n s o l e . l o g ( a F i l e ) ;
  10. GENERADORES: DEFINICIÓN A generator is very similar to a function

    that returns an array, in that a generator has parameters, can be called, and generates a sequence of values. Generators, also known as semicoroutines, are a special case of (and weaker than) coroutines. Wikipedia
  11. CORRUTINA: DEFINICIÓN Components that generalize subroutines to allow multiple entry

    points for suspending and resuming execution at certain locations. Wikipedia
  12. GENERADOR: EJEMPLO v a r q u e e n

    = f u n c t i o n * ( ) { y i e l d " J o h n D e a c o n " ; y i e l d " F r e d d i e M e r c u r y " ; y i e l d " B r i a n M a y " ; y i e l d " R o g e r T a y l o r " ; } ; f o r ( v a r p o f q u e e n ( ) ) { c o n s o l e . l o g ( p ) ; } Usad n o d e - - h a r m o n y
  13. ARGUMENTOS EN GENERADORES: EJERCICIO Escribid un generador que, dado otro

    generador y una función, devuelva un generador m a p . 1. Cread un generador que devuelva una lista de valores (ej. números del 1 al 5). El último elemento tiene que devolverse con return. 2. Usad n e x t ( ) para obtener el siguiente valor de un generador. 3. Cread un generador m a p . 4. Imprimid el resultado usándolo como iterador.
  14. ARGUMENTOS EN GENERADORES: SOLUCIÓN v a r m a p

    G e n = f u n c t i o n * ( g e n , f n ) { i f ( i s G e n e r a t o r ( g e n ) ) { g e n = g e n ( ) ; } v a r c u r r e n t = g e n . n e x t ( ) ; w h i l e ( ! c u r r e n t . d o n e ) { y i e l d f n ( c u r r e n t . v a l u e ) ; c u r r e n t = g e n . n e x t ( ) ; } r e t u r n c u r r e n t . v a l u e ; } ; v a r i s G e n e r a t o r = f u n c t i o n ( o b j ) { r e t u r n o b j & & o b j . c o n s t r u c t o r & & ' G e n e r a t o r F u n c t i o n ' = = o b j . c o n s t r u c t o r . n a m e ; }
  15. ARGUMENTOS EN GENERADORES: CONCLUSIONES n e x t devuelve un

    objeto con dos claves: v a l u e y d o n e y i e l d para la ejecución del generador, dejándola suspendida y i e l d hace que la respuesta de n e x t tenga d o n e : f a l s e r e t u r n hace que la respuesta de n e x t tenga d o n e : t r u e ¿Qué pasa con el último valor de un generador al usarlo como iterador?
  16. YIELD ES UNA PALABRA CLAVE v a r a r

    r g e n = f u n c t i o n * ( a r r ) { a r r . f o r E a c h ( f u n c t i o n ( e l ) { y i e l d e l ; } ) ; } ; v a r s e q = a r r g e n ( [ 1 , 2 , 3 ] ) ; c o n s o l e . l o g ( s e q . n e x t ( ) ) ; c o n s o l e . l o g ( s e q . n e x t ( ) ) ; c o n s o l e . l o g ( s e q . n e x t ( ) ) ;
  17. YIELD ES UNA PALABRA CLAVE g e n - t

    3 c h f e s t / y i e l d _ e x a m p l e . j s : 3 y i e l d e l ; ^ ^ S y n t a x E r r o r : U n e x p e c t e d i d e n t i f i e r a t e x p o r t s . r u n I n T h i s C o n t e x t ( v m . j s : 6 9 : 1 6 ) a t M o d u l e . _ c o m p i l e ( m o d u l e . j s : 4 3 2 : 2 5 ) a t O b j e c t . M o d u l e . _ e x t e n s i o n s . . j s ( m o d u l e . j s : 4 6 7 : 1 0 ) a t M o d u l e . l o a d ( m o d u l e . j s : 3 4 9 : 3 2 ) a t F u n c t i o n . M o d u l e . _ l o a d ( m o d u l e . j s : 3 0 5 : 1 2 ) a t F u n c t i o n . M o d u l e . r u n M a i n ( m o d u l e . j s : 4 9 0 : 1 0 ) a t s t a r t u p ( n o d e . j s : 1 2 3 : 1 6 ) a t n o d e . j s : 1 1 2 8 : 3
  18. YIELD ES UNA PALABRA CLAVE E n u m e

    r a t o r . n e w d o | y | [ 1 , 2 , 3 ] . e a c h d o | x | y < < x e n d e n d . l a z y
  19. MÚLTIPLES PUNTOS DE ENTRADA 1. Cread una sucesión de Pell:

    1. El primer elemento es 0. 2. El segundo elemento es 1. 3. El elemento n es 2 veces el (n-1)-ésimo más el (n-2)-ésimo. 4. El elemento inicial es 1. 2. ¿Qué ocurre si pasáis un parámetro a n e x t ? 3. Modificad el generador del primer punto para que se pueda resetear.
  20. MÚLTIPLES PUNTOS DE ENTRADA v a r p e l

    l = f u n c t i o n * ( ) { v a r a = 0 , b = 1 , c = 0 ; w h i l e ( t r u e ) { y i e l d b ; c = a ; a = b ; b + = c + b ; } } ;
  21. MÚLTIPLES PUNTOS DE ENTRADA SOLUCIÓN 3 v a r p

    e l l = f u n c t i o n * ( ) { v a r a = 0 , b = 1 , c = 0 ; w h i l e ( t r u e ) { v a r r e s u l t = y i e l d b ; i f ( r e s u l t ) { a = 0 ; b = 1 ; } e l s e { c = a ; a = b ; b + = c + b ; } } } ;
  22. EJECUCIÓN DE PELL v a r p e l l

    = f u n c t i o n * ( ) { v a r a = 0 , b = 1 , c = 0 ; w h i l e ( t r u e ) { v a r r e s u l t = y i e l d b ; i f ( r e s u l t ) { a = 0 ; b = 1 ; } e l s e { c = a ; a = b ; b + = c + b ; } } } ; v a r s e q = p e l l ( ) ; c o n s o l e . l o g ( s e q . n e x t ( ) ) ; / / 1 c o n s o l e . l o g ( s e q . n e x t ( ) ) ; / / 2 c o n s o l e . l o g ( s e q . n e x t ( ) ) ; / / 5 c o n s o l e . l o g ( s e q . n e x t ( t r u e ) ) ; / / ?
  23. ÚLTIMO EJERCICIO Crea una función e a c h C

    o n s 2 que, dado un generador, devuelva dos valores consecutivos. Por ejemplo: El generador original devuelve 1, 2, 3, 4, 5, 6... e a c h C o n s 2 devolverá [ 1 , 2 ] ,[ 2 , 3 ] ,[ 3 , 4 ] ,...
  24. ÚLTIMO EJERCICIO v a r e a c h C

    o n s 2 = f u n c t i o n * ( g e n ) { i f ( i s G e n e r a t o r ( g e n ) ) { g e n = g e n ( ) ; } v a r a = g e n . n e x t ( ) , b = g e n . n e x t ( ) ; w h i l e ( ! b . d o n e ) { y i e l d [ a . v a l u e , b . v a l u e ] ; a = b ; b = g e n . n e x t ( ) ; } ; } ;
  25. ÚLTIMO EJERCICIO v a r s q r t 2

    = m a p G e n ( e a c h C o n s 2 ( p e l l ) , f u n c t i o n ( a r r ) { r e t u r n ( a r r [ 0 ] + a r r [ 1 ] ) / a r r [ 1 ] ; } ) ;
  26. RESUMIENDO Son muy parecidos a corrutinas. Se pueden usar como

    un iterador. y i e l d es una keyword Son .
  27. CONTINUACIÓN A continuation is a program frozen in action: a

    single functional object containing the state of a computation. When the object is evaluated, the stored computation is restarted where it left off. , Paul Graham On Lisp
  28. IDEA La idea es utilizar un generador como una continuación.

    Para ello necesitaremos una función a la que llamaremos c u o r e que nos permitirá escribir código como el siguiente: c u o r e ( f u n c t i o n * ( ) { v a r f i r s t F i l e = y i e l d r e a d F i l e ( ' a . t x t ' ) ; v a r s e c o n d F i l e = y i e l d r e a d F i l e ( ' b . t x t ' ) ; c o n s o l e . l o g ( s e c o n d F i l e ) ; c o n s o l e . l o g ( f i r s t F i l e ) ; } ) ( ) ;
  29. THUNKS Denominaremos thunk a una función que devuelve otra función

    cuyo único argumento es un callback. Escribid un thunk de f s . r e a d F i l e . Debe: 1. Admitir un único argumento, el nombre de archivo. 2. Devolver una función que admita como argumento un callback. 3. La función del retorno, al ser llamada con un callback, deberá llamar a f s . r e a d F i l e con el nombre de archivo pasado, ' u t f 8 ' y el callback.
  30. THUNKS v a r f s = r e q

    u i r e ( ' f s ' ) ; v a r r e a d F i l e = f u n c t i o n ( f i l e n a m e ) { r e t u r n f u n c t i o n ( c b ) { f s . r e a d F i l e ( f i l e n a m e , ' u t f 8 ' , c b ) ; } ; } ;
  31. CUORE SEMPLICE Implementad una función c u o r e

    : 1. Debe manejar dos thunks. 2. No debe manejar los errores.
  32. CUORE SEMPLICE v a r c u o r e

    = f u n c t i o n ( g e n ) { r e t u r n f u n c t i o n ( ) { g e n = g e n ( ) ; g e n . n e x t ( ) . v a l u e ( f u n c t i o n ( e r r , d a t a ) { g e n . n e x t ( d a t a ) . v a l u e ( f u n c t i o n ( e r r , d a t a ) { g e n . n e x t ( d a t a ) ; } ) ; } ) ; } ; } ;
  33. CUORE SEMPLICE v a r r f = r e

    a d F i l e ; c u o r e ( f u n c t i o n * ( ) { v a r f i r s t F i l e = y i e l d r f ( ' a . t x t ' ) ; v a r s e c o n d F i l e = y i e l d r f ( ' b . t x t ' ) ; c o n s o l e . l o g ( s e c o n d F i l e ) ; c o n s o l e . l o g ( f i r s t F i l e ) ; } ) ( ) ;
  34. CO Escrito por TJ Holowaychuk Acepta más tipos desde el

    yield: 1. Promesas 2. Array 3. Objetos 4. Generadores 5. Funciones generadoras Existen wrappers para ciertos módulos para que funcionen con c o Para todo lo demás, thunkify.
  35. CO: EJEMPLO v a r f s = r e

    q u i r e ( ' c o - f s ' ) ; v a r c o = r e q u i r e ( ' c o ' ) ; c o ( f u n c t i o n * ( ) { v a r f i r s t F i l e = y i e l d f s . r e a d F i l e ( ' a . t x t ' , ' u t f 8 ' ) ; v a r s e c o n d F i l e = y i e l d f s . r e a d F i l e ( ' b . t x t ' , ' u t f 8 ' ) ; c o n s o l e . l o g ( s e c o n d F i l e ) ; c o n s o l e . l o g ( f i r s t F i l e ) ; } ) ( ) ;
  36. NODE There are interesting language features that we can use

    to extend Node APIs . , Timothy J Fontaine Node.js and the Road Ahead
  37. CHROME Para poder usar generators (probado en Canary): 1. Ir

    a 2. Activar el apartado chrome://flags
  38. KOA: UN EJEMPLO v a r k o a =

    r e q u i r e ( ' k o a ' ) ; v a r a p p = k o a ( ) ; a p p . u s e ( f u n c t i o n * ( n e x t ) { c o n s o l e . l o g ( ' A n t e s ' ) ; y i e l d n e x t ; c o n s o l e . l o g ( ' D e s p u é s ' ) ; } ) ; a p p . u s e ( f u n c t i o n * ( ) { t h i s . b o d y = " M i m a m á m e m i m a " ; } ) ; a p p . l i s t e n ( 4 2 4 2 ) ;
  39. KOA EJERCICIO Utiliza t h i s . c o

    o k i e s . g e t ( n a m e ) y t h i s . c o o k i e s . s e t ( n a m e , v a l u e ) para añadir un texto a la respuesta.
  40. KOA EJERCICIO SOLUCIÓN a p p . u s e

    ( f u n c t i o n * ( n e x t ) { y i e l d n e x t ; v a r b a c k = t h i s . c o o k i e s . g e t ( ' m a j o ' ) ; i f ( b a c k ) { t h i s . b o d y + = " \ n G r a c i a s p o r v o l v e r . " } t h i s . c o o k i e s . s e t ( ' m a j o ' , t r u e ) } ) ;