Sobes.tech
Middle+

Zašto obični generatori omogućavaju pisanje asinhronog koda?

sobes.tech АИ

Одговор од АИ

Обични генератори у JavaScript-у омогућавају писање асинхроног кода захваљујући њиховој способности да заустављају и настављају извршавање, као и да преносе вредности у оба смера (yield и next()).

Ево како то функционише у контексту асинхроности:

  1. Пауза извршавања (yield): Када достигне до оператора yield, генератор се зауставља и враћа вредност. У асинхроном коду, ова вредност може представљати promise или другу "акцију" коју треба извршити асинхроно.

  2. Чекање на асинхрони резултат: Спољни код (нпр. "runner" или обвивка за генератор) добија вредност пренету преко yield. Ако је то promise, чека на његово решавање или одбацивање.

  3. Наставак извршавања (next()): Након што асинхрона операција (решавање promise-а) заврши, асинхрони резултат (вредност promise-а) се враћа назад у генератор преко методе next(). Генератор наставља извршавање од места где је био заустављен.

  4. Пренос резултата: Вредност пренета у 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). Овај механизам омогућава имитацију синхроног тока извршавања за асинхроне операције.