Proč běžné generátory umožňují psát asynchronní kód?
sobes.tech AI
Odpověď od AI
Obvyklé generátory v JavaScriptu umožňují psát asynchronní kód díky jejich schopnosti pozastavit a znovu spustit provádění, stejně jako předávat hodnoty oběma směry (yield a next()).
Zde je, jak to funguje v kontextu asynchronnosti:
-
Pozastavení provádění (
yield): Když dosáhne příkazuyield, generátor se pozastaví a vrátí hodnotu. V asynchronním kódu může tato hodnota představovat promise nebo jinou "akci", kterou je třeba asynchronně provést. -
Čekání na asynchronní výsledek: Vnější kód (například "runner" nebo obal pro generátor) obdrží hodnotu předanou přes
yield. Pokud je to promise, čeká na její vyřešení nebo odmítnutí. -
Obnovení provádění (
next()): Po dokončení asynchronní operace (vyřešení promise) je asynchronní výsledek (hodnota promise) vrácena zpět do generátoru přes metodunext(). Generátor pokračuje v provádění od místa, kde byl pozastaven. -
Předání výsledku: Hodnota předaná do
next()se stává výsledkem výrazuyielduvnitř generátoru. Tím může generátor "získat" výsledek asynchronní operace a pokračovat s ním, jako by kód byl synchronní.
Tento vzor vytváří iluzi synchronního průběhu provádění pro asynchronní operace, což činí kód čitelnějším a lépe spravovatelným ve srovnání s tradičním použitím callbacků nebo složitých řetězců .then().
Příkladem takového obalu je typ co (ačkoliv nyní jsou běžnější async/await, které jsou v podstatě syntaktickým cukrem nad generátory a promise):
// Příklad použití generátoru pro asynchronitu
function* myAsyncGenerator() {
try {
const result1 = yield Promise.resolve(1); // Pozastavení, vrácení promise
console.log('Získali jsme první výsledek:', result1); // Obnovení s předáním výsledku
const result2 = yield new Promise(resolve => setTimeout(() => resolve(2), 500)); // Další asynchronní operace
console.log('Získali jsme druhý výsledek:', result2);
return 'Hotovo'; // Ukončení generátoru
} catch (error) {
console.error('Došlo k chybě:', error);
}
}
// Jednoduchý "runner" pro generátor (zjednodušeno)
function run(generatorFunc) {
const generator = generatorFunc();
function handleNext(newValue) {
const result = generator.next(newValue);
if (!result.done) {
if (result.value instanceof Promise) {
result.value.then(handleNext).catch(handleError);
} else {
handleNext(result.value);
}
} else {
console.log('Generátor byl ukončen s výsledkem:', result.value);
}
}
function handleError(error) {
generator.throw(error);
}
handleNext(); // Spuštění generátoru
}
// Spouštíme náš asynchronní generátor
run(myAsyncGenerator);
V tomto příkladu yield Promise.resolve(1) pozastaví generátor. "Runner" (nebo co) čeká, až se promise vyřeší, a poté znovu spustí generátor, předávající hodnotu 1 přes next(1). Tato hodnota 1 se stává výsledkem yield Promise.resolve(1) uvnitř generátoru, což umožňuje zpracovat ji na následujícím řádku (console.log). Tento mechanismus umožňuje napodobit synchronní tok provádění u asynchronních operací.