canjs / can-stache

Live binding handlebars templates
https://canjs.com/doc/can-stache.html
MIT License
10 stars 13 forks source link

CanJS 3: Memory leak with bindings inside {{#default}} #700

Open RyanMilligan opened 5 years ago

RyanMilligan commented 5 years ago

How often can you reproduce it?

Description: Whenever the content of a {{#default}} block is regenerated, the event handlers for any bindings inside of it are leaked.

Steps to reproduce:

Run the following code:

var VM = DefineMap.extend({
    list: {
        Type: DefineList,
        value() {
            return new DefineList([1, 2]);
        }
    },
    number: {
      value: 0,
      set(val) {
        this.numberSubscriptions = this.__bindEvents.number && this.__bindEvents.number.length;

        return val;
      }
    },
    numberSubscriptions: {
    },

    addItem() {
      this.number++;
    },

    removeItem() {
      this.number--;
    }
});

var vm = new VM();

var template = stache(`
{{<testPartial}}
{{/testPartial}}
Subscriptions: {{numberSubscriptions}}
  <ul>
    {{#switch number}}
      {{#case 1}}
        One!
      {{/case}}
      {{#case 2}}
        Two!
      {{/case}}
      {{#default}}
        Value: {{number}}
      {{/default}}
    {{/switch}}
  </ul>
  <button on:click="addItem()">Add an item</button>
  <button on:click="removeItem()">Remove an item</button>
`);
var frag = template(vm);
document.body.appendChild(frag);

Expected results: The number of event handlers listening to the number event on the view model should remain constant when you click the buttons.

Actual results: When you click the Add or Remove buttons, if the number is set to 1 or 2, the number of Subscriptions doesn't change. But if it's set to any other value, the event bindings grow indefinitely.

Environment: Here's the contents of the package.json file:

  "dependencies": {
    "can-define": "^1.5.5",
    "can-stache": "^3.14.11",
    "can-stache-bindings": "^3.11.10",
    "can-view-nodelist": "^3.1.1",
    "steal": "^1.6.4"
  }
matthewp commented 5 years ago

Is the partial necessary to show this bug? Is reading from __bindEvents?