javascript - microsoft - visual studio community
Implementando flujo de control de coroutine en JavaScript (2)
¿Esto es básicamente lo que hace async / await bajo el capó en ESwhatever?
Realmente no. Es un enfoque diferente para hacer lo mismo. Lo que async/await
convertir es más como
async function foo() {
const bar = await Bar();
bar++;
const baz = await Baz(bar);
return baz;
}
se convierte
function foo() {
return Bar()
.then(bar => {
bar++;
return Baz(bar)
.then(baz => {
return baz;
});
});
}
A continuación se implementa un contenedor de flujo de control que permite que el código asíncrono sea delineado solo por la palabra clave yield
.
¿Esto es básicamente lo que hace async
/ await bajo el capó en ESwhatever?
co(function*() {
console.log(''...'');
yield one();
console.log(''...'');
yield two();
})
function co(gFn) {
var g = gFn();
return Promise.resolve()
.then(go);
function go() {
var result = g.next();
if(result.done) {
return;
}
if(isPromise(result.value)) {
return result.value.then(go); // Promises block until resolution.
}
return Promise.resolve(result);
}
}
function isPromise(o) {
return o instanceof Promise;
}
function one() {
return new Promise(resolve => setTimeout(() => (console.log(''one''), resolve()), 1000));
}
function two() {
return new Promise(resolve => setTimeout(() => (console.log(''two''), resolve()), 1000));
}
Editar:
A la luz de las respuestas que actualicé para tomar en consideración los valores de retorno:
co(function*() {
console.log(''...'');
const result1 = yield one();
console.log(''result1: '', result1);
const result2 = yield two();
console.log(''result2: '', result2);
const result3 = yield[one(), two()];
console.log(''result3: '', result3);
const result4 = yield{
one: one(),
two: two()
};
console.log(''result4: '', result4);
})
function co(gFn) {
var g = gFn();
return Promise.resolve().then(go);
function go() {
var result = g.next(...arguments);
if (isPromise(result.value)) {
return result.value.then(go);
}
if (Array.isArray(result.value)) {
return Promise.all(result.value).then(go);
}
if (isObject(result.value)) {
var o = {};
var promises = Object.keys(result.value).map(k=>result.value[k].then(r=>o[k] = r));
return Promise.all(promises).then(()=>o).then(go);
}
return Promise.resolve(result);
}
}
function isPromise(o) {
return o instanceof Promise;
}
function isObject(val) {
return val && (Object === val.constructor);
}
function one() {
return new Promise(resolve=>setTimeout(()=>(console.log(''one''),
resolve(''result 1'')), 1000));
}
function two() {
return new Promise(resolve=>setTimeout(()=>(console.log(''two''),
resolve(''result 2'')), 1000));
}
Stage 3 Draft / 26 de enero de 2016 Async Functions proporciona ejemplos de tres patrones; Promise
Generator
; Async Functions
; donde los enfoques distintos producen esencialmente el mismo resultado
Tome el siguiente ejemplo, primero escrito usando Promises. Este código encadena un conjunto de animaciones en un elemento, deteniéndose cuando hay una excepción en una animación y devolviendo el valor producido por la animación final ejecutada con éxito.
function chainAnimationsPromise(elem, animations) { let ret = null; let p = currentPromise; for(const anim of animations) { p = p.then(function(val) { ret = val; return anim(elem); }) } return p.catch(function(e) { /* ignore and keep going */ }).then(function() { return ret; }); }
Ya con promesas, el código ha mejorado mucho desde un estilo de devolución de llamada directo, donde este tipo de manejo de bucles y excepciones es un desafío.
Task.js y bibliotecas similares ofrecen una forma de usar generadores para simplificar aún más el código manteniendo el mismo significado:
function chainAnimationsGenerator(elem, animations) { return spawn(function*() { let ret = null; try { for(const anim of animations) { ret = yield anim(elem); } } catch(e) { /* ignore and keep going */ } return ret; }); }
Esta es una mejora notable. Toda la repetición de la promesa por encima y más allá del contenido semántico del código se elimina, y el cuerpo de la función interna representa la intención del usuario. Sin embargo, hay una capa externa de repetitivo para envolver el código en una función de generador adicional y pasarlo a una biblioteca para convertirlo en una promesa. Esta capa debe repetirse en cada función que utiliza este mecanismo para producir una promesa. Esto es tan común en el código JavaScript asíncrono típico, que hay un valor en eliminar la necesidad del texto repetido.
Con las funciones asíncronas, se elimina toda la plantilla repetitiva, dejando solo el código semánticamente significativo en el texto del programa:
async function chainAnimationsAsync(elem, animations) { let ret = null; try { for(const anim of animations) { ret = await anim(elem); } } catch(e) { /* ignore and keep going */ } return ret; }