Właśnie czytałem ten fantastyczny artykuł « Generatory » i wyraźnie podkreśla tę funkcję, która jest funkcją pomocniczą do obsługi funkcji generatora:
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);
}
}
}
co, jak zakładam, jest mniej więcej sposobem async
zaimplementowania słowa kluczowego z async
/ await
. Więc pytanie brzmi, jeśli tak jest, to jaka jest różnica między await
słowem kluczowym a yield
słowem kluczowym? Czy await
zawsze zmienia coś w obietnicę, a yield
nie daje takiej gwarancji? To moje najlepsze przypuszczenie!
Możesz również zobaczyć, jak async
/ await
jest podobne do yield
generatorów w tym artykule, w którym opisuje on funkcję „spawn”, funkcje asynchroniczne ES7 .
javascript
node.js
ecmascript-6
generator
ecmascript-next
Alexander Mills
źródło
źródło
async/await
nie jest częścią ES7. Przeczytaj opis tagu.Odpowiedzi:
yield
można uznać za element składowyawait
.yield
przyjmuje podaną wartość i przekazuje ją wywołującemu. Wzywający może wtedy zrobić cokolwiek zechce z tą wartością (1). Później wywołujący może zwrócić wartość do generatora (viagenerator.next()
), która staje się wynikiemyield
wyrażenia (2) lub błędu, który będzie wyglądał jak wyrzucony przezyield
wyrażenie (3).async
-await
można uznać za używaneyield
. W (1) rozmówcy (czyliasync
-await
kierowcy - podobna do funkcji, którą pisał) będą zawijać wartość w obietnicy stosując podobny algorytmnew Promise(r => r(value)
(uwaga, niePromise.resolve
, ale to nie jest wielka sprawa). Następnie czeka na spełnienie obietnicy. Jeśli spełnia, przekazuje spełnioną wartość z powrotem w (2). Jeśli odrzuca, zgłasza powód odrzucenia jako błąd w (3).Więc użyteczność
async
-await
jest tą maszynerią, która używayield
do rozpakowania uzyskanej wartości jako obietnicy i przekazania jej ustalonej wartości z powrotem, powtarzając się, aż funkcja zwróci swoją ostateczną wartość.źródło
Okazuje się, że istnieje bardzo ścisły związek między
async
/await
a generatorami. I wierzęasync
/await
zawsze będzie budowany na generatorach. Jeśli spojrzysz na sposób transpozycji Babelasync
/await
:Babel bierze to:
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); });
i zamienia to w to
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); }));
ty to Oblicz.
To sprawia, że wygląda na to, że
async
słowo kluczowe jest po prostu tą funkcją opakowującą, ale jeśli tak jest, to poawait
prostu zostanie zamienione wyield
, prawdopodobnie będzie trochę więcej na obrazie później, gdy staną się natywne.Możesz zobaczyć więcej wyjaśnień tutaj: https://www.promisejs.org/generators/
źródło
Słowo
await
kluczowe ma być używane tylko wasync function
s, podczas gdyyield
słowo kluczowe ma być używane tylko w generatorzefunction*
. I one są oczywiście różne - jeden zwraca obietnice, drugi zwraca generatory.Tak,
await
wezwiePromise.resolve
oczekiwaną wartość.yield
po prostu zwraca wartość poza generatorem.źródło
Promise.resolve
używa dokładnie tego samego,new PromiseCapability(%Promise%)
co specyfikacja async / await używa bezpośrednio, po prostu pomyślałem, żePromise.resolve
lepiej to zrozumieć.Promise.resolve
ma dodatkowe zwarcie „IsPromise == true ?, a następnie zwraca tę samą wartość”, którego nie ma w trybie asynchronicznym. Oznacza to, żeawait p
gdziep
jest obietnica, zwróci nową obietnicę, która się spełnip
, podczas gdyPromise.resolve(p)
powrócip
.Promise.cast
i zostało wycofane ze względu na spójność. Ale to nie ma znaczenia, tak naprawdę nie widzimy tej obietnicy.var r = await p; console.log(r);
powinien zostać przekształcony do czegoś takiego jak :,p.then(console.log);
podczas gdyp
może zostać utworzony jako :,var p = new Promise(resolve => setTimeout(resolve, 1000, 42));
więc błędem jest mówić „czekaj na wywołania Promise.resolve”, jest to inny kod, który jest całkowicie oddalony od wywoływanego wyrażenia „await”Promise.resolve
, więc przekształconeawait
wyrażenie , tj.Promise.then(console.log)
zostanie wywołany i wydrukowany42
.tl; dr
Użyj
async
/await
99% czasu na generatorach. Czemu?async
/await
bezpośrednio zastępuje najpopularniejszy przepływ pracy w łańcuchach obietnic, umożliwiając zadeklarowanie kodu tak, jakby był synchroniczny, znacznie upraszczając go.Generatory abstrahują przypadek użycia, w którym można wywołać serię operacji asynchronicznych, które zależą od siebie i ostatecznie będą w stanie „gotowym”. Najprostszym przykładem byłoby przeglądanie wyników, które ostatecznie zwracają ostatni zestaw, ale wywołujesz stronę tylko w razie potrzeby, a nie bezpośrednio po sobie.
async
/await
jest właściwie abstrakcją zbudowaną na generatorach, aby ułatwić pracę z obietnicami.Zobacz bardzo szczegółowe wyjaśnienie Async / Await vs. Generators
źródło
Wypróbuj te programy testowe, które rozumiałem
await
/async
z obietnicami.Program nr 1: bez obietnic nie działa po kolei
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');
Program nr 2: z obietnicami
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');
źródło
Pod wieloma względami generatory są nadzbiorem async / await. Obecnie async / await ma czystsze ślady stosu niż co , najpopularniejsza biblioteka oparta na generatorze async / await. Możesz zaimplementować własny styl async / await za pomocą generatorów i dodać nowe funkcje, takie jak wbudowane wsparcie dla
yield
non-obietnic lub zbudowanie go na podstawie obserwacji RxJS.Krótko mówiąc, generatory zapewniają większą elastyczność, a biblioteki oparte na generatorach mają na ogół więcej funkcji. Ale async / await jest podstawową częścią języka, jest ustandaryzowany i nie zmieni się pod tobą, a do jego używania nie potrzebujesz biblioteki. Mam post na blogu zawierający więcej szczegółów na temat różnicy między async / await a generatorami.
źródło