webentwicklung-frage-antwort-db.com.de

Unterschied zwischen Async/Warten und ES6-Ertrag bei Generatoren

Ich habe gerade diesen fantastischen Artikel gelesen -

https://www.promisejs.org/generators/

und es zeigt deutlich diese Funktion, die eine Hilfsfunktion für die Handhabung von Generatorfunktionen darstellt:

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);
    }
  }
}

was ich vermute ist mehr oder weniger die Art und Weise, wie das async-Schlüsselwort mit async/await implementiert wird. Also ist die Frage, wenn dies der Fall ist, was ist der Unterschied zwischen dem Schlüsselwort await und dem Schlüsselwort yield? Macht await immer etwas zu einem Versprechen, während yield keine Garantie dafür gibt? Das ist meine beste Vermutung!

In diesem Artikel wird beschrieben, wie async/await mit Generatoren vergleichbar ist. Dort beschreibt er die Spawn-Funktion: https://jakearchibald.com/2014/es7-async-functions/

59
Alexander Mills

Nun, es stellt sich heraus, dass zwischen async/await und Generatoren eine sehr enge Beziehung besteht. Und ich glaube, Async/await wird immer auf Generatoren aufgebaut sein. Wenn Sie sich die Art und Weise ansehen, in der Babel async/Erwartung durchdringt:

Babel nimmt das an:

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);

});

und macht es in dieses

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);
}));

du machst die Mathematik.

Dies lässt den Anschein erwecken, als sei das async-Schlüsselwort nur die Wrapper-Funktion. Wenn dies jedoch der Fall ist, wird warten abgewartet und in Rendite verwandelt. Später wird das Bild wahrscheinlich etwas mehr sein, wenn sie native werden.

31
Alexander Mills

yield kann als Baustein von await betrachtet werden. yield nimmt den angegebenen Wert und gibt ihn an den Anrufer weiter. Der Anrufer kann dann mit diesem Wert tun, was er möchte (1). Später kann der Aufrufer dem Generator einen Wert zurückgeben (über generator.next()), der zum Ergebnis des yield-Ausdrucks (2) wird, oder einen Fehler, der durch den yield-Ausdruck (3) ausgelöst zu werden scheint.

async-await kann als yield verwendet werden. Bei (1) wird der Aufrufer (dh der async-await Treiber - ähnlich der von Ihnen bereitgestellten Funktion) den Wert mit einem ähnlichen Algorithmus wie new Promise(r => r(value) in ein Versprechen einbetten (beachten Sie: notPromise.resolve), aber das ist keine große Sache ). Sie wartet dann auf die Lösung des Versprechens. Wenn es erfüllt ist, wird der erfüllte Wert bei (2) zurückgegeben. Wenn es ablehnt, wirft es den Ablehnungsgrund als Fehler bei (3).

Der Nutzen von async-await ist also diese Maschinerie, die yield verwendet, um den erzielten Wert als Versprechen abzuwickeln und den aufgelösten Wert zurückzugeben, wobei er wiederholt wird, bis die Funktion ihren Endwert zurückgibt.

36
Arnavion

was ist der Unterschied zwischen dem Schlüsselwort await und dem Schlüsselwort yield?

Das Schlüsselwort await darf nur in async functions verwendet werden, während das Schlüsselwort yield nur im Generator function*s verwendet wird. Und das ist offensichtlich auch anders - das eine verspricht, das andere die Generatoren.

Macht await immer etwas zu einem Versprechen, während yield keine Garantie dafür gibt?

Ja, await ruft Promise.resolve für den erwarteten Wert auf.

yield liefert nur den Wert außerhalb des Generators.

25
Bergi

tldr;

Use Async/Warten Sie 99% der Zeit auf Generatoren. Warum?

  1. Async/Await ersetzt direkt den gängigsten Arbeitsfluss von Versprechungsketten, sodass Code so deklariert werden kann, als wäre er synchron, wodurch er drastisch vereinfacht wird.

  2. Generatoren abstrahieren den Anwendungsfall, bei dem Sie eine Reihe von asynchronen Operationen aufrufen würden, die voneinander abhängig sind und sich schließlich im Status "erledigt" befinden. Das einfachste Beispiel wäre das Durchsuchen von Ergebnissen, die schließlich den letzten Satz zurückgeben. Sie würden jedoch nur eine Seite nach Bedarf aufrufen, nicht unmittelbar nacheinander.

  3. Async/Await ist eigentlich eine Abstraktion, die auf Generatoren aufgebaut ist, um die Arbeit mit Versprechen zu erleichtern.

Siehe sehr ausführliche Erklärung der Async/Await-Generatoren

4
Jason Sebring

Probieren Sie diese Testprogramme aus, die ich früher mit Versprechen verstanden habe

Programm # 1: ohne Versprechen läuft es nicht in Folge  

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');

programm 2: mit Versprechen:

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
Kamal Kumar

Generatoren sind in vielerlei Hinsicht eine Obermenge von Async/Erwartung. Im Moment hat async/await sauberere Stack-Spuren als co , die populärste async/await-like Generator-basierte Bibliothek. Sie können Ihre eigene Variante von async/await mithilfe von Generatoren implementieren und neue Funktionen hinzufügen, z. B. die integrierte Unterstützung für yield für Nicht-Versprechen oder die Erstellung von RxJS-Observables.

Kurz gesagt, Generatoren bieten Ihnen mehr Flexibilität und generationsbasierte Bibliotheken verfügen in der Regel über mehr Funktionen. Async/await ist jedoch ein zentraler Bestandteil der Sprache. Sie ist standardisiert und wird sich unter Ihnen nicht ändern. Sie benötigen keine Bibliothek, um sie zu verwenden. Ich habe einen blog post mit mehr Details zum Unterschied zwischen async/await und Generatoren.

0
vkarpov15