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/
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.
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.
was ist der Unterschied zwischen dem Schlüsselwort
await
und dem Schlüsselwortyield
?
Das Schlüsselwort await
darf nur in async function
s 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ährendyield
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.
Use Async/Warten Sie 99% der Zeit auf Generatoren. Warum?
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.
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.
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
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');
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');
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.