Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setupSingleBindComputeHandlers leak temporary observables. #1155

Closed
justinbmeyer opened this issue Jul 8, 2014 · 4 comments
Closed

setupSingleBindComputeHandlers leak temporary observables. #1155

justinbmeyer opened this issue Jul 8, 2014 · 4 comments
Labels
Milestone

Comments

@justinbmeyer
Copy link
Contributor

If a {{#if}} block binds to something (ex state in {{#if state}}) and another computes updates state like:

var updateCompute = can.compute(function(){
  map.attr("state", "resolved");
  return 1;
});

This causes an infinite loop.

The reason is complex.

Essentially, {{#if state}} sets up a "singleBindComputeHandler" for performance reasons. This assumes the events to listen for never changes. It never calls __read. __read adds a bindSet to the stack. As __read is never called, any read observables are added to the top of the bind stack. This is updateCompute's bind stack.

The fix is to probably use can.__clearReading / __addReading around

https://github.com/bitovi/canjs/blob/master/compute/compute.js#L235

Or, if that damages performance, to simply push a dummy object on the stack and remove it manually.

This will read

The reason is that {{#if}} creates a compute and reads from it

It's possible for a compute function to set a value which will cause an infinite loop.

For example, something like:

var map = new can.Map({count: 0});

var c1 = can.compute(function(){
  return map.attr("count")+1;
});

var c2 = can.compute(function(){
  map.attr("count", map.count+ 1);
  return 1;
});

Essentially, when c2 sets count, this will immediately update c1. This will fire an update of c1 which reads

@justinbmeyer justinbmeyer modified the milestones: 2.1.4, 2.1.3 Jul 8, 2014
@asavoy
Copy link
Contributor

asavoy commented Jul 9, 2014

+1 - I believe I'm running into this.

@alexisabril
Copy link
Contributor

Potentially related for components(using if to check an attribute on a parent item's scope): http://jsfiddle.net/b65UW/

@justinbmeyer
Copy link
Contributor Author

@asavoy can you share what's breaking for you? I'm unable to recreate this issue. My attempt looked like:

        var map = new can.Map({state: "pending"});
        var source = can.compute(1)
        var number = can.compute(function(){
          map.attr("state", "resolved");
          return source();
        });

        var template = can.stache("{{#map}}<div>{{#if state}}{{number}}{{/if}}</div>{{/map}}")

        var frag = template({
            number: number,
            map: map
        });
        source(2);

        ok(true);

@justinbmeyer
Copy link
Contributor Author

Actually, I found it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants