Skip to content

eventListeners are not removed when removing an element within a controller #838

@dfritsch

Description

@dfritsch

This is related to the memory leak work fixed as part of #592.

That issue fixed cleaning up eventListeners when the controller is removed/replaced within the page. However, there are cases where the element with an action can be updated within the controller (such as an input or button changing in response to other actions in a form).

I've altered the example from that issue to reproduce the new issue:

<html>

<head>
  <title>EventListenerMaps memory leak</title>
  <script type="module">
    import { Application, Controller } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js"
    window.Stimulus = Application.start()
    Stimulus.register("boosts", class extends Controller {
      doClick() { process(500) }
    })
  </script>
  <script>
    function process(count) {
      let i = 0
      let handler = setInterval(function () {
        if (++i > count) {
          clearInterval(handler)
        } else {
          element = document.getElementById("replace-in-controller")
          element.replaceWith(element.cloneNode(true))
        }
      }, 1)
    }
  </script>
</head>

<body>
  <div data-controller="boosts">
    <div id="replace-in-controller">
      To reproduce:
      <ul>
        <li>Check heap snapshot</li>
        <li>Click "trigger leak" button</li>
        <li>Check heap snapshot again</li>
      </ul>
      <button data-action="click->boosts#doClick">trigger leak</button>
    </div>
  </div>
</body>

</html>

Comparing the heap before and after clicking this button, you can see the detached elements relating to event listeners:

Image

In this case it appears that we execute

this.delegate.bindingDisconnected(binding)
to clean up the action, which does not specify clearEventListeners so they are not removed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions