Search code examples
javascripthtmldommemoryv8

Why the onevent properties are being treated as closure in memory snapshot?


When I take a memory snapshot after triggering the largeClosures() and stopAndClear() click event handler. I can see the (closure) row contains these event handlers.

These event handlers are bound to the DOM element by Using onevent properties.

For example:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p>Analyze the impact of closures on memory</p>
  <p>
    <button onclick="largeClosures()">
      Closures maintain hold on large string
    </button>
  </p>
  <p>
    <button onclick="smallClosures()">
      Closures maintain hold only on small strings
    </button>
  </p>
  <p>
    <button onclick="evalClosures()">Closures with <code>eval</code></button>
  </p>
  <button onclick="stopAndClear()">Stop and clear</button>
  <script>
    var closures = [];

    function createLargeClosure() {
      var largeStr = new Array(1000000).join("x");
      return function lC() {
        return largeStr;
      };
    }

    function createSmallClosure() {
      var smallStr = "x";
      var largeStr = new Array(1000000).join("x");
      return function sC() {
        return smallStr;
      };
    }

    function createEvalClosure() {
      var smallStr = "x";
      var largeStr = new Array(1000000).join("x");
      return function eC() {
        eval("");
        return smallStr;
      };
    }

    function largeClosures() {
      closures.push(createLargeClosure());
    }

    function smallClosures() {
      closures.push(createSmallClosure());
    }

    function evalClosures() {
      closures.push(createEvalClosure());
    }

    function clear() {
      closures.length = 0;
    }

    function stopAndClear() {
      clear();
    }
  </script>
</body>

</html>

Memory snapshot(using Microsoft Edge Developer Tool - Memory):

enter image description here

As you can see, the (closure) contains these two click event handlers. Each of them has 32 bytes of memory allocated. Why they are being treated as a closure? The traditional closure should be like lC, sC, and eC functions.


Solution

  • The event handlers capture the surrounding context in which they were created, forming a closure to maintain access to variables and functions that were in scope when they were defined.

    In your HTML code, when you define an onclick attribute for a button, like button onclick="largeClosures()", you are essentially creating a function (closure) that includes the entire scope where the function is defined, which includes the closures array and all the functions defined within the tag. This behavior is intended and is a characteristic of JavaScript closures.

    The lC, sC, and eC functions separately, the onclick attributes in the HTML also create closures that include references to those functions, and this is why you're seeing the memory allocation for those click event handlers.

    So, instead of using HTML attributes for event handling, attach event listeners programmatically using JavaScript. This gives you more control over scope and memory. You can attach and remove event listeners as needed, potentially reducing the closure-related memory consumption.