Kodėl įprasti generatoriai leidžia rašyti asinchroninį kodą?
sobes.tech AI
Atsakymas iš AI
Įprasti generatoriai JavaScript leidžia rašyti asinchroninį kodą dėka jų gebėjimo sustabdyti ir atnaujinti vykdymą, taip pat perduoti reikšmes abiem kryptimis (yield ir next()).
Štai kaip tai veikia asinchronijos kontekste:
-
Vykdymo sustabdymas (
yield): Kai pasiekiamayieldinstrukcija, generatorius sustoja ir grąžina reikšmę. Asinchroniniame kode ši reikšmė gali būti pažadas (promise) arba kita "veikla", kuri turi būti vykdoma asinchroniškai. -
Laukiama asinchroninio rezultato: Išorinė dalis (pvz., "rėmėjas" arba generatoriaus apvalkalas) gauna perduotą reikšmę per
yield. Jei tai promise, jis laukia jo išsprendimo arba atmetimo. -
Vykdymo atnaujinimas (
next()): Po asinchroninės operacijos (promise išsprendimo) pabaigos, asinchroninis rezultatas (promise reikšmė) grąžinamas atgal į generatorių pernext()metodą. Generatorius tęsia vykdymą nuo sustojimo vietos. -
Rezultato perdavimas: Reikšmė, perduota
next(), tampayieldišraiškos rezultatu generatoriaus viduje. Taip generatorius gali "gauti" asinchroninės operacijos rezultatą ir tęsti darbą su juo, tarsi kodas būtų sinchroninis.
Šis modelis sukuria iliuziją, kad asinchroninės operacijos vykdomos sinchroniškai, todėl kodas tampa lengviau skaitomas ir valdomas, palyginti su tradiciniu callback'ų ar sudėtingų .then() grandinių naudojimu.
Pavyzdžiui, tokio naudojimo pavyzdys yra co tipo apvalkalas (nors dabar dažniau naudojami async/await, kurie iš esmės yra sintaksinis cukrus virš generatorių ir promise'ų):
// Pavyzdys, naudojant generatorių asinchronijai
function* myAsyncGenerator() {
try {
const result1 = yield Promise.resolve(1); // Sustabdyti, grąžinti promise
console.log('Pirmas rezultatas:', result1); // Tęsti perduodant rezultatą
const result2 = yield new Promise(resolve => setTimeout(() => resolve(2), 500)); // Dar viena asinchroninė operacija
console.log('Antras rezultatas:', result2);
return 'Paruošta'; // Generatoriaus pabaiga
} catch (error) {
console.error('Klaida:', error);
}
}
// Paprastas "rėmėjas" generatoriui (supaprastintas)
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('Generatorius baigėsi su rezultatu:', result.value);
}
}
function handleError(error) {
generator.throw(error);
}
handleNext(); // Generatoriaus paleidimas
}
// Paleidžiame mūsų asinchroninį generatorių
run(myAsyncGenerator);
Šiame pavyzdyje yield Promise.resolve(1) sustabdo generatorių. "Rėmėjas" (arba co) laukia, kol promise bus išspręstas, ir tada vėl paleidžia generatorių, perduodamas reikšmę next(1). Ši reikšmė 1 tampa yield Promise.resolve(1) rezultatu generatoriaus viduje, leidžiant ją apdoroti kitame žingsnyje (console.log). Šis mechanizmas leidžia imituoti sinchroninio vykdymo srautą asinchroninėms operacijoms.