समझें कि गार्बेज कलेक्टर कैसे काम करता है, लीक से बचने के लिए वीक रेफरेंस का उपयोग करें, और debounce तथा throttle के साथ महँगे काम को सुचारू बनाएँ।
इस पाठ को Kodokon में खोलेंV8 का गार्बेज कलेक्टर पहुँच-योग्यता (reachability) पर आधारित है: कोई वस्तु तभी संग्रहणीय बन जाती है जैसे ही संदर्भों की कोई श्रृंखला उसे रूट्स (स्टैक, सक्रिय स्कोप, ग्लोबल्स) से नहीं जोड़ती। GC जनरेशनल है: नई वस्तुएँ *nursery* में रहती हैं, जिन्हें बार-बार और तेज़ी से संग्रहित किया जाता है (scavenge); बचे हुए को पुरानी पीढ़ी में पदोन्नत किया जाता है, जिसे इंक्रीमेंटल mark-and-sweep संभालता है। शास्त्रीय लीक GC से नहीं आतीं बल्कि उन संदर्भों से आती हैं जिन्हें आप भूल गए: Map-आधारित कैश, वे लिसनर जो कभी अलग नहीं किए जाते, बड़ी वस्तुओं को कैप्चर करने वाले क्लोज़र।
const strongCache = new Map();
const weakCache = new WeakMap();
let session = { user: "ada" };
strongCache.set(session, "data");
weakCache.set(session, "data");
session = null;
// Map: the key retains the object -> memory leak
// WeakMap: the entry becomes collectableएक WeakMap अपनी कुंजियों को नहीं रोकता: जब कोई कुंजी कहीं और से पहुँच से बाहर हो जाती है, तो पूरी प्रविष्टि गायब हो जाती है। डिज़ाइन परिणाम: कुंजियाँ वस्तुएँ (या अपंजीकृत सिंबल) होनी चाहिए, और यह संरचना न तो इटरेबल है और न ही मापनीय - इसका आकार उजागर करना GC के व्यवहार को प्रकट कर देगा, जो नियतात्मक नहीं है। WeakRef और आगे जाता है: यह आपको एक सीधा वीक रेफरेंस देता है, जिसे deref() से डिरेफरेंस किया जाना चाहिए।
let config = { theme: "dark" };
const ref = new WeakRef(config);
function readTheme() {
const target = ref.deref();
return target ? target.theme : "default";
}
console.log(readTheme()); // "dark"
config = null;
// After a GC pass, deref() may
// return undefined: plan a fallback.अनुभूत-परफ़ॉर्मेंस की तरफ, उच्च-आवृत्ति वाले इवेंट (scroll, resize, input, mousemove) प्रति सेकंड सैकड़ों कॉल ट्रिगर कर सकते हैं। दो पूरक रणनीतियाँ: debounce फ़ंक्शन को केवल एक शांत अवधि के बाद चलाता है (टाइप-करते-समय-खोज के लिए आदर्श), जबकि throttle प्रति अंतराल अधिकतम एक निष्पादन की गारंटी देता है (स्क्रॉलिंग को ट्रैक करने के लिए आदर्श)।
function debounce(fn, delay) {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(
() => fn.apply(this, args),
delay
);
};
}function throttle(fn, interval) {
let last = 0;
return function (...args) {
const now = Date.now();
if (now - last >= interval) {
last = now;
fn.apply(this, args);
}
};
}ref.deref() क्या लौटा सकता है?undefined यदि वह संग्रहित हो चुकी हैnull यदि वस्तु संग्रहित हो चुकी है