Khachatryan-dev

Closure-ներ async կոդում JavaScript-ում

Այս հոդվածում կուսումնասիրենք, թե closure-ները ինչպես են աշխատում async կոդում

Aram
Khachatryan

Closure-ներ async կոդում JavaScript-ում


Closure-ները JavaScript-ում թույլ են տալիս ֆունկցիաներին հիշել իրենց ստեղծման սքոփը։ Երբ closure-ը միավորվում է asynchronous կոդի հետ՝ ինչպես setTimeout, async/await կամ Promise, սկսում են առաջանալ չհասկացված իրավիճակներ։ Այս հոդվածում կուսումնասիրենք, թե closure-ները ինչպես են աշխատում async կոդում, ինչ խնդիրներ են առաջանում, և ինչպես կարելի է դրանք լուծել։




Closure և setTimeout՝ loop-ում


  
// Թիվ 1 սխալ օրինակ
for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 1000);
}

// Արդյունք (1 վայրկյան անց):
// 3
// 3
// 3
  

Բացատրություն․


  • Ի՞նչ է տեղի ունենում։ `setTimeout`-ի callback-ը closure է, որը պահում է հղում դեպի `i`։
  • Երբ loop-ը ավարտվում է, `i = 3`, closure-ները տեսնում են հենց այդ արժեքը։

  
// Լուծում՝ օգտագործել let (բլոկ սքոփով i)
for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 1000);
}

// Արդյունք՝ 0, 1, 2
  

Կամ՝ IIFE օգտագործելով var-ի դեպքում․


  
for (var i = 0; i < 3; i++) {
  (function(index) {
    setTimeout(() => {
      console.log(index);
    }, 1000);
  })(i);
}
  



Closure async/await ֆունկցիաներում


  
function createLogger() {
  const username = "Aram";

  return async function logMessage() {
    await new Promise(res => setTimeout(res, 1000));
    console.log("Hello", username);
  };
}

const logger = createLogger();
logger(); // 1 վայրկյան անց => Hello Aram
  

Ինչ է տեղի ունենում․


  • `username`-ը պահպանվում է closure-ի մեջ։
  • Թեև `await`-ը սպասեցնում է ֆունկցիան, closure-ը շարունակում է պահել իր lexical միջավայրը։



Closure և Promise callback-ներ


  
function fetchData() {
  const token = "secret-token-123";

  return fetch("/api/data").then(() => {
    console.log("Token used:", token);
  });
}

fetchData();
  

Բացատրություն․


  • `.then()` callback-ը closure է, որը պահում է `token`-ը։
  • Սա շատ հարմար է auth headers, կամ scoped config փոխանցելու համար։



Ցուցանիշների վտանգը async կոդում


  
function delayedCounter() {
  for (var i = 0; i < 5; i++) {
    setTimeout(() => console.log("Counter:", i), i * 500);
  }
}

delayedCounter();
  

Խնդիրը՝ կրկին closure + var:


  • Բոլոր log-երը տպում են նույն արժեքը (5), closure-ը պահում է վերջին `i`-ի հղումը։

Լուծումը՝ օգտագործել let կամ closure-ի կլոն (IIFE):


  
// Ավելի պարզ let տարբերակ
for (let i = 0; i < 5; i++) {
  setTimeout(() => console.log("Counter:", i), i * 500);
}
  



Եզրակացություն


Closure-ները հիանալի գործիք են async կոդում կարգ ու կանոն պահելու համար։ Սակայն եթե օգտագործում ենք `var`, կամ սխալ կերպով փոխանցում փոփոխականներ, կարող ենք անսպասելի արդյունքներ ստանալ։ Միշտ հիշիր՝ closure-ները պահում են *հղում*, ոչ թե արժեք, եթե դա object-type փոփոխական է։


Օգտագործի՛ր `let` կամ IIFE closure-ներ, async/await-ի հետ աշխատելիս զգուշացիր loop-երում, և closure-դ դարձրու մաքուր ու կանխատեսելի։


Buy me a coffee
  • 0
  • 25

Բացահայտիր Նոր գիտելիքներ

Մեկնաբանություններ
No data
Մեկնաբանություն չկա։ Կարող ես լինել առաջինը։
Գրել մեկնաբանություն
ՄԵկնաբանություն ավելացնելու համար պետք է մուտք գործելՄուտք