Zašto obični generatori omogućavaju pisanje asinhronog koda?
sobes.tech АИ
Одговор од АИ
Обични генератори у JavaScript-у омогућавају писање асинхроног кода захваљујући њиховој способности да заустављају и настављају извршавање, као и да преносе вредности у оба смера (yield и next()).
Ево како то функционише у контексту асинхроности:
-
Пауза извршавања (
yield): Када достигне до оператораyield, генератор се зауставља и враћа вредност. У асинхроном коду, ова вредност може представљати promise или другу "акцију" коју треба извршити асинхроно. -
Чекање на асинхрони резултат: Спољни код (нпр. "runner" или обвивка за генератор) добија вредност пренету преко
yield. Ако је то promise, чека на његово решавање или одбацивање. -
Наставак извршавања (
next()): Након што асинхрона операција (решавање promise-а) заврши, асинхрони резултат (вредност promise-а) се враћа назад у генератор преко методеnext(). Генератор наставља извршавање од места где је био заустављен. -
Пренос резултата: Вредност пренета у
next()постаје резултат изразаyieldунутар генератора. Тако, генератор може "да добије" резултат асинхроне операције и да настави са њим, као да је код синхронизован.
Овај образац ствара илузију синхроног тока извршавања за асинхроне операције, чинећи код читљивијим и управљивијим у поређењу са традиционалним коришћењем callback-ова или сложених ланаца .then().
Пример таквог облика је тип co (иако су сада распрострањенији async/await, који у суштини представљају синтаксички шећер над генераторима и promise-има):
// Пример коришћења генератора за асинхроност
function* myAsyncGenerator() {
try {
const result1 = yield Promise.resolve(1); // Заустављање, враћање promise-а
console.log('Први резултат:', result1); // Наставак са пренетом вредношћу
const result2 = yield new Promise(resolve => setTimeout(() => resolve(2), 500)); // Још једна асинхрона операција
console.log('Други резултат:', result2);
return 'Готово'; // Завршетак генератора
} catch (error) {
console.error('Грешка:', error);
}
}
// Једноставан "runner" за генератор (поједностављено)
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('Генератор је завршен са резултатом:', result.value);
}
}
function handleError(error) {
generator.throw(error);
}
handleNext(); // Покретање генератора
}
// Покрећемо наш асинхрони генератор
run(myAsyncGenerator);
У овом примеру, yield Promise.resolve(1) зауставља генератор. "Runner" (или co) чека да се promise реши, а затим поново покреће генератор, преносећи вредност 1 преко next(1). Ова вредност 1 постаје резултат yield Promise.resolve(1) унутар генератора, омогућавајући да се обради у следећој линији (console.log). Овај механизам омогућава имитацију синхроног тока извршавања за асинхроне операције.