tut-ES6-promises-generators



tut-ES6-promises-generators

2 2


tut-ES6-promises-generators

Presentacion interactiva sobre Promesas, Generadores, Iteradores y Async/Await en ES6

On Github burabure / tut-ES6-promises-generators

Codigo Asincrono

en ES2015/2016

http://goo.gl/86v9kK

Nicolás Fernández @elBuraBure CPO / CTO

ES5.1 y código asíncrono

Hasta hace poco los patrones de código asíncrono consistian basicamente de Callbacks, lo que supone los siguientes problemas:

  • Inversion del control
  • Confusion de los inputs con los outputs
  • El manejo de errores se complejiza considerablemente
  • El codigo se vuelve dificil de mantener y entender
- (2:00) - Explicar JS = ES, Explicar ES5, ES6/2015. - Inversion => un frag. de tu app es controlado por una funciona utilitaria

El problema de Confianza

// (1) tu programa hasta ahora

funcionAsincrona( function(){
    // (2) todo tu programa despues
});

¿ Quien controla funcionAsincrona ?

¿ Puedes confiar que funcionAsincrona provisione y ejecute (2) correctamente ?

¿ Que tanto depende tu codigo de funcionAsincrona ?

- (4:00) - Quien controla la libreria?, sabes como funciona por dentro? - Que pasa cuando cambian versiones?, o si nececitas cambiar la libreria? - Tu App se acopla fuertemente a una libreria utilitaria

Ejemplo tweets con Callbacks en jQuery

// VAMOS A BUSCAR UN JSON
// parte 1: Un nuevo Callback
$.ajax({
  url: '//jsbin.com/cinuna/6.json',
  dataType: 'json',
  success: function(response){
              var json = response;
              /* Nos devuelve el siguiente json
                { tweets:
                    user: "LaViejaDeLaEsquina.com",
                    [
                      "//jsbin.com/cinuna/4.json",
                      "//jsbin.com/cinuna/5.json"
                    ]
                }
              */

              // VAMOS A BUSCAR UN JSON
              // parte 2: El Callback contraataca
              $.ajax({
                url: json.tweets[0], // "//jsbin.com/cinuna/4.json"
                dataType: 'json',
                success:  function(response){
                            var tweet1 = response;
                            // Nos devuelve el siguiente json
                            /* {body: "#MasterChefMenudeReyes Charquicán
                             (pero ÉSE Charquicán, con longaniza ¡con TODO!)"} */

                            // VAMOS A BUSCAR UN JSON
                            // parte 3: El retorno del Callback
                            $.ajax({
                              url: json.tweets[1], // "//jsbin.com/cinuna/5.json"
                              dataType: 'json',
                              success:  function(response){
                                          var tweet2 = response;
                                          // Nos devuelve el siguiente json
                                          /* {body: "A todo esto? En qué pasillo del Unimarc
                                           encuentro jabalí? #MasterChefMenuDeReyes"} */

                                          // Aqui esta el código que nos importa... ¬_¬
                                          console.log(tweet1,tweet2);
                                          // ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
                                        },
                              error: function(err){ console.log(err); }
                            });
                },
                error: function(err){ console.log(err); }
            });
  },
  error: function(err){ console.log(err); }
});
                
(5:00) Vamos a buscar unos tweets con jQuery Primero traemos un Json con el perfil del usuario y una lista de urls de sus Tweets Parte1...

Como podemos solucionar estos problemas?

Las nuevas versiones de EcmaScript estan siendo implementadas en Browsers y Runtimes como io.js y Node.js.

Estas incluyen Patrones e APIs nativas para manejo de codigo asincrono de manera adecuada.

- (7:00) - Les voy a mostrar unos patrones que simplifican el codigo asincrono - Estos patrones pueden ocuparlos nativamente en ES2015/16 - Pero son solo patrones, pueden usarlos con cualquier libreria, ambiente o lenguajes

Promesas, ¿Que son?

Una Promesa representa el resultado de una operación asincrona o diferida (aplazada)

El objeto "Promise" se puede encontrar uno de 3 estados:

  • pending: estado inicial, no se ha completado ni rechazado
  • fulfilled: operacion finalizada correctamente
  • rejected: operacion fallida
- (8:00) - Primer Patron y el mas Importante! - Es un Valor "Prometido"

sintaxis

var promise = new Promise(function(resolve, reject) {
  // hacer algo, posiblemente async
  muchasCosasLaRaja = true;

  if (muchasCosasLaRaja) {
    resolve("Promesa Resuelta!");
  }
  else {
    reject(Error("Promesa Rechazada!"));
  }
});
- (8:30) - La Promesa se construye con dos funciones - resolve y reject - resolve es como return - reject es como throw - Es tu trabajo envolver cosas asincronas en una promesa

Soporte Nativo en Browsers?

- (9:30) - Todos menos IE - Pero Edge lo hace bien!, un aplauso

Como Ocuparlas en todos los navegadores y runtimes?

- (10:00) - Babel es un transpilador... - jQuery hace las cosas como se le da la gana y la api no es estandar, pero no es muy diferente
Promesas: Hello World
(10:30) Cuando lleguen a su casa pueden jugar con esta presentacion interactiva Voy a dejarles el link y un codigo qr al final para que le saquen una foto
Promesas: Bomba asincrona
(SKIP)
Promesas: AJAX
(12:30)
Promesas: Promise.all
(14:00)

Ejemplo tweets con Callbacks en jQuery

$.ajax({
  url: '//jsbin.com/cinuna/6.json',
  dataType: 'json',
  success: function(response){
              var json = response;
              $.ajax({
                url: json.tweets[0], // "//jsbin.com/cinuna/4.json"
                dataType: 'json',
                success:  function(response){
                            var tweet1 = response;
                            $.ajax({
                              url: json.tweets[1],
                              dataType: 'json',
                              success:  function(response){
                                          var tweet2 = response;
                                          console.log(tweet1,tweet2);
                                        },
                              error: function(err){ console.log(err); }
                            });
                },
                error: function(err){ console.log(err); }
            });
  },
  error: function(err){ console.log(err); }
});
                
(16:00)

Ejemplo tweets con Promesas

get('//jsbin.com/cinuna/6.json')
  .then(function(response){
    var json = JSON.parse(response);
    var tweetsPrometidos = [get(json.tweets[0]), get(json.tweets[1])];
    return Promise.all(tweetsPrometidos);
  })
  .then(function(tweets){
    for(var tweet of tweets) {
      console.log(JSON.parse(tweet));
    }
  })
  .catch(function(err){ console.log(err); });
- (16:15)

Promesas vs callbacks

vs callbacks, las promesas nos permiten:

  • Componer y razonar claramente sobre nuestro codigo asincrono
  • Simplificar una cadena de codigo asincrono, no mas nesting
  • Simplifican el manejo de errores en un 9000% ™ ©
  • Solucionar en parte el problema de inversion de control
  • No confundir los inputs con los outputs
- (17:00) - Si me prestaron atencion hasta ahora ya tienen lo mas importante de la charla

Generadores, ¿Que son?

Los Generadores son funciones que pueden ser pausadas y reanudadas en otro momento.

Estas pausas en realidad CEDEN la ejecucion al resto de tu programa, es decir no bloquean la ejecucion.

Los Generadores retornan (generan) un objeto "Iterator" (iterador)

- (18:00) - Segundo Patron! - Los Generadores son funciones que puedes pausar - Puedes hacer que te retornen muchos valores - Cada vez que pausas la funcion, puedes retornar un valor - Retornan un iterador

Iteradores, ¿Que Son?

Los iteradores fundamentalmente son un patrón que nos permite trabajar con colecciones por medio de abstracciones de alto nivel

Un Iterador es un objeto que sabe como acceder a los items de una colección uno a la vez mientras que mantiene la referencia a su posición actual en la secuencia.

- (18:30)

Iteradores, parte 2

En ES2015 las colecciones (arrays, maps, sets) son objetos iteradores

Los iteradores pueden ser iterados/recorridos con:

  • for
  • for each
  • for of
  • for in
  • map()
  • filter()
  • comprensiones de colecciones/secuecias..
- (18:45)

Sintaxis

// la funcion foo es un generador
function* foo() { // la sintaxis para un generador es " function* "
    // yield cede la ejecucion, retorna el valor
    // a la derecha y pausa el generador
    yield 1;
    yield 2;
    yield 3;
}

var iter = foo(); // iter recibe un objeto iterador

// next() ejecuta el iterador hasta el siguiente yield
// dentro del mismo y retorna un objeto con el valor a la derecha de este
iter.next(); // { value: 1, done: false }
iter.next(); // { value: 2, done: false }
iter.next(); // { value: 3, done: false }
- (19:00)
Generadores: Hello World
(19:45)
Generadores: Generando Iteradores
(SKIP)
Generadores: Iterando Iteradores
(SKIP)
Generadores: Colecciones Flojas
(SKIP)
Generadores: Insercion de Valores
(SKIP)
Generadores: Control de Flujo
(SKIP)
Generadores: Delegando Iteradores
(SKIP)

Funciones Asincronas, ¿Que son?

Draft para ES7

la funcion Async permite esperar( await ) una promesa pausando la ejecucion sin bloquear. Al resolverse la promesa retorna el valor.

[https://github.com/lukehoban/ecmascript-asyncawait]

- (20:30) - Tenemos Promesas, tenemos generadores, que pasa si los mesclamos?

Sintaxis

async function loadStory() {
  try {
    // await espera a que la llamada asincrona
    // se complete antes de entregar el valor}
    var story = await getJSON('story.json');
    console.log("OK!", story);
  } catch (err) {
    console.log("Algo se rompio!: " + err.message);
  }
  document.querySelector('.spinner').style.display = 'none';
}
- (21:30)
Async / Await: tweets
(22:30)

Ejemplo tweets con Promesas

get('//jsbin.com/cinuna/6.json')
  .then(function(response){
    var json = JSON.parse(response);
    var tweetsPrometidos = [get(json.tweets[0]), get(json.tweets[1])];
    return Promise.all(tweetsPrometidos);
  })
  .then(function(tweets){
    for(var tweet of tweets) {
      console.log(JSON.parse(tweet));
    }
  })
  .catch(function(err){ console.log(err); });
- (23:00)

Ejemplo tweets con Async / Await

(async function() {
  try {
    var data = await get('//jsbin.com/cinuna/6.json');
    var j = JSON.parse(data);
    var tweets = await Promise.all([get(j.tweets[0]), get(j.tweets[1])]);

    for(var tweet of tweets) { console.log(JSON.parse(tweet)); }
  }
  catch (err){ console.log(err); }
})();
- (23:15)

Ejemplo tweets con Async / Await v2

var getTweets = (async function() {
  try {
    var data = await get('//jsbin.com/cinuna/6.json');
    var j = JSON.parse(data);
    var tweets = await Promise.all([get(j.tweets[0]), get(j.tweets[1])]);
    return tweets;
  }
  catch (err){ return(err); }
})();

getTweets.then(function(tweets){
  for(var tweet of tweets) { console.log(JSON.parse(tweet)); }
});
- (23:45)

Polyfill

Si no queremos jugar con features de ES2016, por que su api no esta bien definida aun, podemos ocupar una funcion simple como spawn o librerias como co y generadores

- (SKIP)
Spawn: tweets
(SKIP)

Podemos pensar en estas caracteristicas de ES2015/2016

de la siguiente manera:

Sync Async function T Promise function* Iterator ???

La pregunta es: "que nos devuelve un generador asincrono?"

(24:30)

Generadores Asíncronos, ¿Que son?

Draft para ES7

Los Generadores Asíncronos nos permiten consumir una coleccion de valores asincrona como si se tratara de una coleccion sincrona.

Los Generadores Asíncronos nos devuelven un tipo "Observable"

[https://github.com/jhusain/asyncgenerator]

- (25:00)

Ejemplo Drag & drop

Los Generadores Asíncronos aun no tienen una API definida, polyfill o transpilacion a ES5

Pero nos permitiran escribir operaciónes asincronas complejas, de una manera declarativa y clara.

function getMouseDrags(elmt) {
  var mouseDowns = Observable.fromEvent(elmt, "mousedown"),
  var documentMouseMoves = Observable.fromEvent(document.body, "mousemove"),
  var documentMouseUps = Observable.fromEvent(document.body, "mouseup");

  return mouseDowns.concatMap(mouseDown =>
    documentMouseMoves.takeUntil(documentMouseUps));
};

var image = document.createElement("img");
document.body.appendChild(image);

getMouseDrags(image).forEach(dragEvent => {
  image.style.left = dragEvent.clientX;
  image.style.top = dragEvent.clientY;
});
- (25:30) - Eventos como un "array" asincrono

Ejemplo Observacion Asincrona

Incluso podremos declarar operaciónes de Observacion Asincrona.

async function testFn() {
  var writer = new AsyncStreamWriter("/...");

  for(var x on new AsyncStreamReader("/...")) {
    await writer.write(x);
  }
}
- (26:00)

- (26:30) - Javascript es el unico lenguaje capaz de compartir codigo y datos en tiempo real entre servidor y cliente - El lenguaje esta empujando fuertemente a un desarrollo agily una actulizacion constante del mismo - Creo que es el uno de los mejores lenguajes para afrontar los problemas de hoy; big data, cloud, networking, concurrency

Gracias

http://goo.gl/86v9kK

contribuciones y correcciones en https://github.com/burabure/tut-ES6-promises-generators

Nicolás Fernández @elBuraBure CPO / CTO