On Github burabure / tut-ES6-promises-generators
Hasta hace poco los patrones de código asíncrono consistian basicamente de Callbacks, lo que supone los siguientes problemas:
// (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// 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...
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 lenguajesUna Promesa representa el resultado de una operación asincrona o diferida (aplazada)
El objeto "Promise" se puede encontrar uno de 3 estados:
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
$.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)
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)
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 iteradorLos 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)En ES2015 las colecciones (arrays, maps, sets) son objetos iteradores
Los iteradores pueden ser iterados/recorridos con:
// 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)
Draft para ES7
la funcion Async permite esperar( await ) una promesa pausando la ejecucion sin bloquear. Al resolverse la promesa retorna el valor.
- (20:30) - Tenemos Promesas, tenemos generadores, que pasa si los mesclamos?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)
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)
(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)
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)
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)La pregunta es: "que nos devuelve un generador asincrono?"
(24:30)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"
- (25:00)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
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)
contribuciones y correcciones en https://github.com/burabure/tut-ES6-promises-generators
Nicolás Fernández @elBuraBure CPO / CTO