Ich habe gerade diesen fantastischen Artikel « Generatoren » gelesen und er hebt diese Funktion deutlich hervor, die eine Hilfsfunktion für die Handhabung von Generatorfunktionen ist:
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);
}
}
}
Ich gehe davon aus, dass das async
Schlüsselwort mehr oder weniger mit async
/ implementiert wird await
. Die Frage ist also, wenn dies der Fall ist, was zum Teufel ist dann der Unterschied zwischen dem await
Schlüsselwort und dem yield
Schlüsselwort? Wird await
aus etwas immer ein Versprechen, während yield
es keine solche Garantie gibt? Das ist meine beste Vermutung!
Sie können auch sehen, wie async
/ mit Generatoren await
ähnlich ist, yield
in diesem Artikel, in dem er die asynchronen Funktionen der ' Spawn' -Funktion ES7 beschreibt .
javascript
node.js
ecmascript-6
generator
ecmascript-next
Alexander Mills
quelle
quelle
async/await
ist nicht Teil von ES7. Bitte lesen Sie die Tag-Beschreibung.Antworten:
yield
kann als Baustein von betrachtet werdenawait
.yield
Nimmt den angegebenen Wert und gibt ihn an den Anrufer weiter. Mit diesem Wert kann der Anrufer dann machen, was er will (1). Später kann der Aufrufer dem Generator (viagenerator.next()
) einen Wert zurückgeben, der das Ergebnis desyield
Ausdrucks (2) wird, oder einen Fehler, der vomyield
Ausdruck (3) ausgelöst zu werden scheint .async
-await
kann als verwendet werdenyield
. Bei (1) wird der Aufrufer (dh derasync
-await
Treiber - ähnlich der von Ihnen geposteten Funktion) den Wert mit einem ähnlichen Algorithmus wie in ein Versprechen einschließennew Promise(r => r(value)
(beachten Sie, nichtPromise.resolve
, aber das ist keine große Sache). Es wartet dann auf die Lösung des Versprechens. Wenn es erfüllt, gibt es den erfüllten Wert bei (2) zurück. Wenn es ablehnt, wirft es den Ablehnungsgrund als Fehler bei (3).Der Nutzen von
async
-await
ist also diese Maschinerie, mityield
der der erbrachte Wert als Versprechen ausgepackt und der aufgelöste Wert zurückgegeben wird. Wiederholen Sie diesen Vorgang, bis die Funktion ihren endgültigen Wert zurückgibt.quelle
Nun, es stellt sich heraus, dass es eine sehr enge Beziehung zwischen
async
/await
und Generatoren gibt. Und ich glaubeasync
/await
werde immer auf Generatoren bauen. Wenn Sie sich ansehen, wie Babel transpiliertasync
/await
:Babel nimmt das:
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); });
und macht daraus
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); }));
Du machst die Mathematik.
Dies macht es aussehen wie das
async
Schlüsselwort nur , dass Wrapper - Funktion ist, aber wenn das der Fall ist , dannawait
wird nur verwandelt sich inyield
, wird es wahrscheinlich ein bisschen mehr auf das Bild sein später , wenn sie heimisch werden.Weitere Erklärungen hierzu finden Sie hier: https://www.promisejs.org/generators/
quelle
Das
await
Schlüsselwort darf nur inasync function
s verwendet werden, während dasyield
Schlüsselwort nur in Generatoren verwendet werden sollfunction*
. Und diese sind natürlich auch anders - der eine gibt Versprechen zurück, der andere gibt Generatoren zurück.Ja,
await
ruftPromise.resolve
den erwarteten Wert auf.yield
ergibt nur den Wert außerhalb des Generators.quelle
Promise.resolve
verwendet genau das gleichenew PromiseCapability(%Promise%)
, was die async / await-Spezifikation direkt verwendet. Ich dachte nur, esPromise.resolve
ist besser zu verstehen.Promise.resolve
hat einen zusätzlichen Kurzschluss "IsPromise == true? dann gleichen Wert zurückgeben", den Async nicht hat. Das heißt,await p
wop
ein Versprechen ist, wird ein neues Versprechen zurückgegeben, das aufgelöst wirdp
, währendPromise.resolve(p)
es zurückkehren würdep
.Promise.cast
und aus Konsistenzgründen veraltet. Aber es spielt keine Rolle, wir sehen dieses Versprechen sowieso nicht wirklich.var r = await p; console.log(r);
sollte in etwas wie: transformiert werdenp.then(console.log);
, währendp
es als: erstellt werden könntevar p = new Promise(resolve => setTimeout(resolve, 1000, 42));
, also ist es falsch zu sagen " Warte auf Aufrufe Promise.resolve", es ist ein anderer Code, der völlig weit von dem Ausdruck " Warten" entfernt ist, der aufruftPromise.resolve
, also der transformierteawait
Ausdruck dhPromise.then(console.log)
aufgerufen und ausgedruckt werden42
.tl; dr
Verwenden Sie
async
/await
99% der Zeit über Generatoren. Warum?async
/await
ersetzt direkt den gängigsten Workflow von Versprechensketten, sodass Code als synchron deklariert werden kann, was ihn erheblich vereinfacht.Generatoren abstrahieren den Anwendungsfall, in dem Sie eine Reihe von asynchronen Operationen aufrufen würden, die voneinander abhängen und sich schließlich in einem "erledigten" Zustand befinden. Das einfachste Beispiel wäre das Durchblättern von Ergebnissen, die schließlich den letzten Satz zurückgeben, aber Sie würden eine Seite nur nach Bedarf aufrufen, nicht unmittelbar nacheinander.
async
Ichawait
bin eigentlich eine Abstraktion, die auf Generatoren aufbaut, um das Arbeiten mit Versprechungen zu erleichtern.Siehe sehr ausführliche Erläuterung von Async / Await vs. Generators
quelle
Versuchen Sie, diese Testprogramme , die ich verwendet , um zu verstehen
await
/async
mit Versprechungen.Programm Nr. 1: Ohne Versprechen läuft es nicht nacheinander
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 Nr. 2: mit Versprechungen
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');
quelle
Generatoren sind in vielerlei Hinsicht eine Obermenge von Async / Warten. Im Moment hat async / await sauberere Stack-Traces als co , die beliebteste async / await-ähnliche generatorbasierte lib. Sie können Ihre eigene Variante von Async / Warten mithilfe von Generatoren implementieren und neue Funktionen hinzufügen, z. B. integrierte Unterstützung für
yield
Nichtversprechen oder Aufbau auf RxJS-Observablen.Kurz gesagt, Generatoren bieten Ihnen mehr Flexibilität und generatorbasierte Bibliotheken bieten im Allgemeinen mehr Funktionen. Async / await ist jedoch ein zentraler Bestandteil der Sprache. Es ist standardisiert und ändert sich unter Ihnen nicht. Sie benötigen keine Bibliothek, um es zu verwenden. Ich habe einen Blog-Beitrag mit weiteren Details zum Unterschied zwischen Async / Warten und Generatoren.
quelle