Sobes.tech
Middle+

Ինչու սովորական գեներատորները թույլ են տալիս գրել ասինխրոնային կոդ:

sobes.tech AI

Պատասխան AI-ից

Անհատական ​​գեներատորները JavaScript-ում թույլ են տալիս գրել ասինխրոնային կոդ՝ շնորհիվ նրանց կարողության դադարեցնել և վերականգնել կատարման գործընթացը, ինչպես նաև փոխանցել արժեքներ երկու ուղղություններով (yield և next()

Ահա թե ինչպես է դա աշխատում ասինխրոնության համատեքստում՝

  1. Կատարման դադարեցում (yield): Երբ հասնում է yield հրահանգին, գեներատորը դադարեցնում է և վերադարձնում արժեքը։ Ասինխրոնային կոդում, այս արժեքը կարող է լինել մի խոստում (promise) կամ այլ "գործողություն", որը պետք է կատարվի ասինխրոնորեն։

  2. Ասինխրոն արդյունքի սպասում: Բաց կոդը (օրինակ, "ռաներ" կամ գեներատորի համար պատվածք) ստանում է yield-ով փոխանցված արժեքը։ Եթե դա խոստում է, այն սպասում է նրա լուծմանը կամ մերժմանը։

  3. Կատարման վերականգնում (next()): Երբ ասինխրոն գործողությունը (խոստումի լուծումը) ավարտվում է, ասինխրոն արդյունքը (խոստումի արժեքը) փոխանցվում է վերադառնալով գեներատորին next() մեթոդով։ Գեներատորը շարունակում է կատարմանը այն տեղից, որտեղ դադարեցվել էր։

  4. Արդյունքի փոխանցում: next()-ին փոխանցված արժեքը դառնում է yield արտահայտության արդյունքը գեներատորի ներսում։ Այսպիսով, գեներատորը կարող է "ստանալ" ասինխրոն գործողության արդյունքը և շարունակել նրա հետ աշխատել, կարծես կոդը սինխրոն լինի։

Այս մոդելը ստեղծում է սինխրոնային կատարման հորինվածություն՝ ասինխրոն գործողությունների համար, ինչը դարձնում է կոդը ավելի ընթեռնելի և կառավարելի՝ համեմատած ավանդական callback-ների կամ բարդ շղթաների .then() օգտագործման հետ։

Օրինակ, այսպիսի օգտագործման օրինակ է co տիպի պատվածքը (համենայն դեպս այժմ ավելի տարածված են async/await, որոնք հիմնականում սինտակսիկ շաքար են գեներատորների և խոստումների վրա).`

// Օրինակ՝ գեներատորի օգտագործում ասինխրոնության համար
function* myAsyncGenerator() {
  try {
    const result1 = yield Promise.resolve(1); // Դադարեցում, խոստում վերադարձում
    console.log('Առաջին արդյունքը ստացանք:', result1); // Վերականգնում արդյունքի փոխանցմամբ

    const result2 = yield new Promise(resolve => setTimeout(() => resolve(2), 500)); // Այլ մի ասինխրոն գործողություն
    console.log('Երկրորդ արդյունքը ստացանք:', result2);

    return 'Պատրաստ է'; // Գեներատորի ավարտ
  } catch (error) {
    console.error('Սխալ է տեղի ունեցել:', error);
  }
}

// Պարզ "ռաներ" գեներատորի համար (պարզեցված)
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) դադարեցնում է գեներատորը։ "Ռաները" (կամ co) սպասում է, մինչև խոստումը լուծվի, և ապա վերականգնում է գեներատորը, փոխանցելով արժեքը next(1)-ով։ Այս արժեքը 1 դառնում է yield Promise.resolve(1)-ի արդյունքը գեներատորի ներսում, ինչը թույլ է տալիս այն մշակել հաջորդ տողում (console.log)։ Այս մեխանիզմը թույլ է տալիս իմիտացիա ստեղծել սինխրոնային հոսքի համար ասինխրոն գործողությունների։