Closure-ներ և Memory Leak-եր JavaScript-ում
JavaScript-ում closure-ները թույլ են տալիս ֆունկցիաներին պահպանել մուտքի տվյալները իրենց lexical scope-ից, նույնիսկ այն ժամանակ, երբ այդ ֆունկցիան այլևս չի գտնվում նույն սքոփում։ Չնայած closure-ները հզոր գործիք են՝ երբեմն դրանք կարող են առաջացնել հիշողության արտահոսք (memory leak), եթե դրանք սխալ են օգտագործվում։
Այս հոդվածում կքննարկենք՝ ինչպե՞ս կարող են closure-ները բերել հիշողության արտահոսքի, ինչպիսի՞ սխալներ են հաճախ արվում և ինչպե՞ս կանխել դրանք։
DOM-ի Event Listener-ները և Closure-ները
function attachListener() {
const largeData = new Array(1000000).fill('🔥');
document.getElementById('btn').addEventListener('click', function handleClick() {
console.log('Clicked!', largeData[0]);
});
}
attachListener();
Խնդիրը․
- `largeData` զանգվածը մնաց հիշողության մեջ, քանի որ closure-ը պահեց նրա հղումը, չնայած այն այլևս մեզ պետք չէ։
- Եթե այս ֆունկցիան կանչվում է բազմիցս, կուտակվում են event listener-ներ՝ յուրաքանչյուրը պահելով իր սեփական closure-ը։
Լուծում․
- Օգտագործել `.removeEventListener()`՝ անհրաժեշտության դեպքում։
- Պահել միայն այն տվյալները, որոնք իրոք պետք են closure-ի մեջ։
Closure-ներ Timer-ների և setInterval-ի մեջ
function startTimer() {
const userData = { name: "Aram", age: 28 };
setInterval(() => {
console.log("Tick for", userData.name);
}, 1000);
}
startTimer();
Խնդիրը․
- `userData`-ն երբեք garbage collect չի լինում, քանի որ closure-ը պահում է այն `setInterval`-ի մեջ։
- Եթե component-ը կամ էջը վերաթողարկվի, այդ interval-ը դեռ շարունակում է գործել։
Լուծում․
- Օգտագործել `clearInterval()` կամ `clearTimeout()` համապատասխան պահերին։
- Օգտագործել cleanup մեխանիզմներ, օրինակ՝ React-ի `useEffect` hook-ի return callback-ը։
Detached DOM Element-ներ
function createElement() {
const bigData = new Array(1000000).fill("💾");
const el = document.createElement('div');
el.onclick = function () {
console.log(bigData[0]);
};
return el;
}
const element = createElement();
// էլեմենտը երբեք չի ավելացվում DOM-ի մեջ, բայց closure-ը դեռ պահում է bigData-ն
Խնդիրը․
- DOM element-ը պահվում է closure-ով, closure-ը պահում է մեծ տվյալներ, բայց ոչ մի բան իրականում չի օգտագործվում։
Լուծում․
- Մաքրել անպետք DOM nodes, եթե դրանք ավելորդ են։
- Հստակ բաժանել դոմ մանիպուլյացիան closure-ից։
Եզրակացություն
Closure-ները հզոր են, բայց ինչպես ցանկացած հզոր գործիք՝ կարող են բերել խնդիրների, եթե սխալ օգտագործվեն։ Memory leak-երը կարող են առաջանալ, երբ closure-ները պահում են մեծ տվյալներ, որոնք այլևս չեն օգտագործվում, սակայն garbage collect-ը չի մաքրվում։ Լավ պրակտիկան closure-ները մաքուր պահելն է՝ օգտագործելով միայն անհրաժեշտ տվյալներ և ավելորդ կապեր չստեղծելով։
Եթե closure-ների հետ աշխատում ես Event Listener-ներում, interval-ներում կամ DOM-ի հետ, միշտ մտածիր՝ "արդյոք այս տվյալը ինձ իրականում դեռ պետք է"։