Diferencia entre rendimiento async/await y ES6 con generadores


Estaba leyendo este fantástico artículo -

Https://www.promisejs.org/generators /

Y resalta 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 hipotetizo es más o menos la forma en que la palabra clave async se implementa con async/await. Así que la pregunta es, si ese es el caso, entonces ¿cuál es la diferencia entre la palabra clave await y la palabra clave yield? Does await always turn algo en una promesa, mientras que yield no hace tal garantía? ¡Esa es mi mejor suposición!

También puedes ver cómo async/await es similar a yield con generadores en este artículo donde describe la función 'spawn': https://jakearchibald.com/2014/es7-async-functions /

Author: Alexander Mills, 2016-03-24

6 answers

yield puede considerarse que es el componente básico de await. yield toma el valor que se le ha dado 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 yield (2), o un error que parecerá ser arrojado por la expresión yield (3).

async-await puede considerarse que utiliza yield. En (1) la persona que llama (es decir, el async-await conductor-similar para la función que ha publicado) envolverá el valor en una promesa utilizando un algoritmo similar a new Promise(r => r(value) (nota, no Promise.resolve, pero eso no es gran cosa). Entonces espera que la promesa se resuelva. Si cumple, pasa el valor cumplido de nuevo en (2). Si rechaza, arroja la razón de rechazo como un error en (3).

Así que la utilidad de async-await es esta maquinaria que utiliza yield para desenvolver el valor producido como una promesa y pasar su valor resuelto de nuevo, repitiendo hasta el la función devuelve su valor final.

 33
Author: Arnavion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-24 11:23:36

Bueno, resulta que hay una relación muy estrecha entre async/await y los generadores. Y creo que async / await siempre se construirá en generadores. Si nos fijamos en la forma en que Babel transpila async / await:

Babel toma esto:

this.it('is a test', async function () {

    const foo = await 3;
    const bar = await new Promise(function (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(function (resolve) {
        resolve('7');
    });
    const baz = bar * foo;
    console.log(baz);
}));

Haz las cuentas.

Esto hace que parezca que la palabra clave async es solo esa función de envoltura, pero si ese es el caso, entonces await se convierte en yield, probablemente habrá un poco más a la imagen más adelante cuando se convierten en nativos.

 30
Author: Alexander Mills,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-27 08:10:35

¿Cuál es la diferencia entre la palabra clave await y la palabra clave yield?

La palabra clave await solo se usa en async function s, mientras que la palabra clave yield solo se usa en generator function* s. Y esas son obviamente diferentes también - una devuelve promesas, la otra devuelve generadores.

¿await siempre convierte algo en una promesa, mientras que yield no hace tal garantía?

Sí, await llamará a Promise.resolve en el valor esperado.

yield solo produce el valor fuera del generador.

 25
Author: Bergi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-24 11:26:10

Pruebe este programa de prueba que utilicé para 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');
 3
Author: Kamal Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-14 05:20:32

Tldr;

Utilice Async / Await el 99% de las veces sobre generadores. ¿Por qué?

  1. Async / Await reemplaza directamente el flujo de trabajo más común de las cadenas de promesa permitiendo que el código sea declarado como si fuera sincrónico, simplificándolo dramáticamente.

  2. Los generadores resumen el caso de uso en el que llamaría a una serie de operaciones asincrónicas que dependen unas de otras y que eventualmente estarán en un estado "hecho". El ejemplo más simple sería la búsqueda de resultados que eventualmente devuelva el último conjunto, pero solo llamaría a una página según sea necesario, no inmediatamente en sucesión.

  3. Async / Await es en realidad una abstracción construida sobre generadores para facilitar el trabajo con promesas.

Ver una explicación muy detallada de Async / Await vs. Generators

 3
Author: Jason Sebring,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-23 22:50:21

En muchos sentidos, los generadores son un superconjunto de async/await. En este momento async/await tiene trazas de pila más limpias que co, la lib basada en generador similar a async/await más popular. Puede implementar su propio tipo de async / await usando generadores y agregar nuevas características, como soporte incorporado para yield en no promesas o construirlo en observables RxJS.

Así que, en resumen, los generadores le dan más flexibilidad y las bibliotecas basadas en generadores generalmente tienen más características. Pero async / await es un núcleo parte del lenguaje, está estandarizado y no cambiará bajo ti, y no necesitas una biblioteca para usarlo. Tengo una entrada de blog con más detalles sobre la diferencia entre async/await y generators.

 0
Author: vkarpov15,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-03 16:03:01