Closure-ներ async կոդում JavaScript-ում
Այս հոդվածում կուսումնասիրենք, թե closure-ները ինչպես են աշխատում async կոդում
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-դ դարձրու մաքուր ու կանխատեսելի։
- 0
- 25