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" asincronoIncluso 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