Estaba leyendo este fantástico artículo « Generadores » y destaca claramente esta función, que es una función auxiliar para manejar las funciones del generador:
function async(makeGenerator){
return function () {
var generator = makeGenerator.apply(this, arguments);
function handle(result){
// result => { done: [Boolean], value: [Object] }
if (result.done) return Promise.resolve(result.value);
return Promise.resolve(result.value).then(function (res){
return handle(generator.next(res));
}, function (err){
return handle(generator.throw(err));
});
}
try {
return handle(generator.next());
} catch (ex) {
return Promise.reject(ex);
}
}
}
que supongo que es más o menos la forma en que asyncse implementa la palabra clave con async/ await. Entonces, la pregunta es, si ese es el caso, ¿cuál es la diferencia entre la awaitpalabra clave y la yieldpalabra clave? ¿ awaitSiempre convierte algo en una promesa, mientras yieldque no ofrece tal garantía? ¡Esa es mi mejor suposición!
También puede ver cómo async/ awaites similar ayield generadores en este artículo donde describe la función 'spawn' de las funciones asíncronas de ES7 .
javascript
node.js
ecmascript-6
generator
ecmascript-next
Alexander Mills
fuente
fuente

async/awaitno es parte de ES7. Lea la descripción de la etiqueta.Respuestas:
yieldpuede considerarse el componente básico deawait.yieldtoma el valor que se le da y lo pasa a la persona que llama. La persona que llama puede hacer lo que desee con ese valor (1). Más tarde, la persona que llama puede devolver un valor al generador (víagenerator.next()) que se convierte en el resultado de layieldexpresión (2), o un error que parecerá arrojado por layieldexpresión (3).async-awaitse puede considerar su usoyield. En (1) la persona que llama (es decir, elasync-awaitpiloto - similar a la función informados) envolverá el valor de una promesa usando un algoritmo similar anew Promise(r => r(value)(nota, noPromise.resolve, pero eso no es un gran problema). Luego espera a que se resuelva la promesa. Si cumple, devuelve el valor cumplido a (2). Si rechaza, arroja el motivo del rechazo como un error en (3).Entonces, la utilidad de
async-awaites esta maquinaria que usayieldpara desenvolver el valor entregado como una promesa y devolver su valor resuelto, repitiendo hasta que la función devuelve su valor final.fuente
Bueno, resulta que hay una relación muy estrecha entre
async/awaity generadores. Y creoasync/awaitsiempre serán construidos en los generadores. Si miras la forma en que Babel transpilaasync/await:Babel toma esto:
this.it('is a test', async function () { const foo = await 3; const bar = await new Promise(resolve => resolve('7')); const baz = bar * foo; console.log(baz); });y lo convierte en esto
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { return step("next", value); }, function (err) { return step("throw", err); }); } } return step("next"); }); }; } this.it('is a test', _asyncToGenerator(function* () { // << now it's a generator const foo = yield 3; // <<< now it's yield, not await const bar = yield new Promise(resolve => resolve(7)); const baz = bar * foo; console.log(baz); }));haces las matemáticas.
Esto hace que parezca que la
asyncpalabra clave es solo esa función contenedora, pero si ese es el caso,awaitsimplemente se convierte enyield, probablemente habrá un poco más en la imagen más adelante cuando se conviertan en nativas.Puede ver más explicaciones para esto aquí: https://www.promisejs.org/generators/
fuente
La
awaitpalabra clave solo debe usarse enasync functions, mientras que layieldpalabra clave solo debe usarse en generadoresfunction*. Y esos también son obviamente diferentes: uno devuelve promesas, el otro devuelve generadores.Sí,
awaitllamaráPromise.resolveal valor esperado.yieldsimplemente produce el valor fuera del generador.fuente
Promise.resolveusa exactamente lo mismonew PromiseCapability(%Promise%)que la especificación async / await usa directamente, solo pensé quePromise.resolvees mejor entenderlo.Promise.resolvetiene un cortocircuito extra "IsPromise == true? then return same value" que async no tiene. Es decir,await pdondephay una promesa devolverá una nueva promesa que resuelvep, mientrasPromise.resolve(p)que volveríap.Promise.castestaba disponible y estaba en desuso por razones de coherencia. Pero no importa, realmente no vemos esa promesa de todos modos.var r = await p; console.log(r);debería transformarse en algo como:,p.then(console.log);mientras queppodría crearse como:,var p = new Promise(resolve => setTimeout(resolve, 1000, 42));por lo que es incorrecto decir " await llama a Promise.resolve", es algún otro código totalmente alejado de la expresión 'await' que invocaPromise.resolve, por lo que laawaitexpresión transformada , es decirPromise.then(console.log), se invoca y se imprime42.tl; dr
Uso
async/await99% del tiempo sobre generadores. ¿Por qué?async/awaitreemplaza directamente el flujo de trabajo más común de las cadenas de promesas permitiendo que el código se declare como si fuera sincrónico, simplificándolo drásticamente.Los generadores abstraen el caso de uso en el que llamarías a una serie de operaciones asíncronas que dependen unas de otras y que eventualmente estarán en un estado "terminado". El ejemplo más simple sería buscar resultados que eventualmente devuelvan el último conjunto, pero solo llamaría a una página según sea necesario, no inmediatamente en sucesión.
async/awaites en realidad una abstracción construida sobre generadores para facilitar el trabajo con promesas.Vea una explicación muy detallada de Async / Await vs.Generadores
fuente
Pruebe estos programas de prueba que solía entender
await/asynccon promesas.Programa # 1: sin promesas no se ejecuta en secuencia
function functionA() { console.log('functionA called'); setTimeout(function() { console.log('functionA timeout called'); return 10; }, 15000); } function functionB(valueA) { console.log('functionB called'); setTimeout(function() { console.log('functionB timeout called = ' + valueA); return 20 + valueA; }, 10000); } function functionC(valueA, valueB) { console.log('functionC called'); setTimeout(function() { console.log('functionC timeout called = ' + valueA); return valueA + valueB; }, 10000); } async function executeAsyncTask() { const valueA = await functionA(); const valueB = await functionB(valueA); return functionC(valueA, valueB); } console.log('program started'); executeAsyncTask().then(function(response) { console.log('response called = ' + response); }); console.log('program ended');Programa # 2: con promesas
function functionA() { return new Promise((resolve, reject) => { console.log('functionA called'); setTimeout(function() { console.log('functionA timeout called'); // return 10; return resolve(10); }, 15000); }); } function functionB(valueA) { return new Promise((resolve, reject) => { console.log('functionB called'); setTimeout(function() { console.log('functionB timeout called = ' + valueA); return resolve(20 + valueA); }, 10000); }); } function functionC(valueA, valueB) { return new Promise((resolve, reject) => { console.log('functionC called'); setTimeout(function() { console.log('functionC timeout called = ' + valueA); return resolve(valueA + valueB); }, 10000); }); } async function executeAsyncTask() { const valueA = await functionA(); const valueB = await functionB(valueA); return functionC(valueA, valueB); } console.log('program started'); executeAsyncTask().then(function(response) { console.log('response called = ' + response); }); console.log('program ended');fuente
En muchos sentidos, los generadores son un superconjunto de async / await. En este momento, async / await tiene rastros de pila más limpios que co , la biblioteca basada en generador async / await más popular. Puede implementar su propia versión de async / await usando generadores y agregar nuevas características, como soporte integrado para
yieldno promesas o compilarlo en observables RxJS.Entonces, en resumen, los generadores le brindan más flexibilidad y las bibliotecas basadas en generadores generalmente tienen más funciones. Pero async / await es una parte central del lenguaje, está estandarizado y no cambiará debajo de usted, y no necesita una biblioteca para usarlo. Tengo una publicación de blog con más detalles sobre la diferencia entre async / await y generators.
fuente