Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> JavaScript

Closure ก่อให้เกิด Memory Leak ใน JavaScript และการป้องกัน

Closure และ Memory Leak

Closure: Inner Function ที่เข้าถึง Variable ของ Outer Function ได้ แม้ Outer Return แล้ว

ตัวอย่างปัญหา

<script>
  window.onload = function parentFunction(arg1) {
    var a = arg1; // Captured by Closure
    
    return function childFunction(arg2) {
      alert(a + ' ' + arg2); // ใช้ a
    };
  };
  
  var val = parentFunction('outer val');
  val('inner val'); // Alert: 'outer val inner val'
  // 'a' ค้างใน Memory ตลอดที่ val ยังอยู่
</script>

Memory Leak Pattern: Accumulating Closures

var cache = {};
function getData(key) {
  if (!cache[key]) {
    // Heavy Computation
    const largeData = new Array(1000000).fill('x');
    cache[key] = function() { return largeData; }; // Closure captures largeData!
  }
  return cache[key]();
}
// cache ไม่เคย Clear → Memory Leak

วิธีป้องกัน

1. Nullify References

function parentFunction(arg1) {
  var a = arg1;
  const handler = function childFunction(arg2) {
    alert(a + ' ' + arg2);
  };
  // ตัด Reference เมื่อไม่ใช้
  return {
    handler,
    destroy() { a = null; } // Manual Cleanup
  };
}

2. ใช้ IIFE แยก Scope (ตัวอย่างต้นฉบับ)

window.onload = function parentFunction() {
  var obj1 = function childFunction1() {
    document.write('the leak is avoided');
  };
  
  (function childFunction2() {
    var obj2 = document.getElementById('closure');
    obj2.onclick = obj1; // obj1 ไม่ Capture parent Scope
  })();
};

3. WeakMap สำหรับ Cache

const cache = new WeakMap();
function getData(obj) {
  if (!cache.has(obj)) {
    cache.set(obj, heavyComputation(obj));
  }
  return cache.get(obj);
}
// Obj ถูก GC → Cache Entry หาย Auto

4. Event Listener Cleanup

element.addEventListener('click', handler);
// ตอน Destroy:
element.removeEventListener('click', handler);