generador - symbol iterator javascript
Diferencia entre asÃncrono/espera y rendimiento ES6 con generadores (6)
¿Cuál es la diferencia entre la palabra clave de
await
y la palabra clave deyield
?
La palabra clave
await
solo se debe usar en
async function
, mientras que la palabra clave de
yield
solo se debe usar en
function*
generadoras
function*
s.
Y estos también son obviamente diferentes: uno devuelve promesas, el otro devuelve generadores.
¿La
await
siempre convierte algo en una promesa, mientras que elyield
no ofrece tal garantía?
Sí,
Promise.resolve
llamará a
Promise.resolve
en el valor esperado.
yield
solo produce el valor fuera del generador.
Estaba leyendo este fantástico artículo.
https://www.promisejs.org/generators/
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);
}
}
}
lo que supongo es más o menos la forma en que la palabra clave asincrónica se implementa con
async/await
.
Entonces la pregunta es, si ese es el caso, ¿cuál es la diferencia entre la palabra clave de
await
y la palabra clave de
yield
?
¿La
await
siempre convierte algo en una promesa, mientras que el
yield
no ofrece tal garantía?
Esa es mi mejor suposición!
También puede ver cómo async / await es similar al rendimiento con generadores en este artículo donde describe la función ''spawn'': https://jakearchibald.com/2014/es7-async-functions/
tldr;
Use 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 promesa permitiendo que el código se declare como si fuera síncrono, simplificándolo drásticamente.
-
Los generadores resumen el caso de uso donde llamaría a una serie de operaciones asíncronas que dependen unas de otras y eventualmente estarán en un estado "hecho". El ejemplo más simple sería buscar resultados que finalmente 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 los Generadores para facilitar el trabajo con promesas.
Vea una explicación muy detallada de Async / Await vs. Generators
Bueno, resulta que hay una relación muy estrecha entre async / wait y generadores. Y creo que async / await siempre se basará en generadores. Si observa la forma en que Babel transpila async / wait:
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);
}));
Tú haces los cálculos.
Esto hace que parezca que la palabra clave asíncrona es solo esa función de contenedor, pero si ese es el caso, la espera se convertirá en rendimiento, probablemente habrá un poco más en la imagen más adelante cuando se conviertan en nativos.
Puede ver más explicaciones para esto aquí: https://www.promisejs.org/generators/
En muchos sentidos, los generadores son un superconjunto de asíncrono / espera.
En este momento, async / await tiene rastros de pila más limpios que
co
, la lib basada en el generador async / await-like más popular.
Puede implementar su propio sabor de asíncrono / espera usando generadores y agregar nuevas características, como soporte integrado para
yield
en no promesas o construirlo en observables RxJS.
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á bajo 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 generadores.
Pruebe estos programas de prueba que solía entender en espera / asíncrono 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'');
yield
puede ser considerado como la piedra angular de la
await
.
yield
toma el valor que se le da y se lo pasa a la persona que llama.
La persona que llama puede hacer lo que quiera con ese valor (1).
Más tarde, la persona que llama puede devolver un valor al generador (a través de
generator.next()
) que se convierte en el resultado de la expresión de
yield
(2), o un error que parecerá arrojado por la expresión de
yield
(3).
async
-
await
puede ser considerado para usar el
yield
.
En (1) la persona que llama (es decir, el controlador
async
-
await
- similar a la función que publicó) envolverá el valor en una promesa utilizando un algoritmo similar al
new Promise(r => r(value)
(nota,
no
Promise.resolve
, pero eso no es gran cosa). Luego espera a que se resuelva la promesa. Si se cumple, pasa el valor cumplido nuevamente a (2). Si rechaza, arroja la razón de rechazo como un error en (3).
Entonces, la utilidad de
async
-
await
es esta maquinaria que usa el
yield
para desenvolver el valor cedido como una promesa y devolver su valor resuelto, repitiendo hasta que la función devuelva su valor final.