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 async
se implementa la palabra clave con async
/ await
. Entonces, la pregunta es, si ese es el caso, ¿cuál es la diferencia entre la await
palabra clave y la yield
palabra clave? ¿ await
Siempre convierte algo en una promesa, mientras yield
que no ofrece tal garantía? ¡Esa es mi mejor suposición!
También puede ver cómo async
/ await
es 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/await
no es parte de ES7. Lea la descripción de la etiqueta.Respuestas:
yield
puede considerarse el componente básico deawait
.yield
toma 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 layield
expresión (2), o un error que parecerá arrojado por layield
expresión (3).async
-await
se puede considerar su usoyield
. En (1) la persona que llama (es decir, elasync
-await
piloto - 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
-await
es esta maquinaria que usayield
para 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
/await
y generadores. Y creoasync
/await
siempre 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
async
palabra clave es solo esa función contenedora, pero si ese es el caso,await
simplemente 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
await
palabra clave solo debe usarse enasync function
s, mientras que layield
palabra clave solo debe usarse en generadoresfunction*
. Y esos también son obviamente diferentes: uno devuelve promesas, el otro devuelve generadores.Sí,
await
llamaráPromise.resolve
al valor esperado.yield
simplemente produce el valor fuera del generador.fuente
Promise.resolve
usa exactamente lo mismonew PromiseCapability(%Promise%)
que la especificación async / await usa directamente, solo pensé quePromise.resolve
es mejor entenderlo.Promise.resolve
tiene un cortocircuito extra "IsPromise == true? then return same value" que async no tiene. Es decir,await p
dondep
hay una promesa devolverá una nueva promesa que resuelvep
, mientrasPromise.resolve(p)
que volveríap
.Promise.cast
estaba 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 quep
podrí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 laawait
expresión transformada , es decirPromise.then(console.log)
, se invoca y se imprime42
.tl; dr
Uso
async
/await
99% del tiempo sobre generadores. ¿Por qué?async
/await
reemplaza 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
/await
es 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
/async
con 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
yield
no 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