tldr; Observations created inside other observations should always be entered in the queue after the outer observation. If the outer observation is updated, the child observation should be "stopped" (all handlers unbound and stops listening on its dependencies).
This might eliminate one of the core abilities of nodeLists - the need to recursively unbinding child nodelists!
Background
Take some example stache code like:
{{#if show}}
<div>{{foo}}</div>
{{/if}}
This gets compiled into the following pseudo observations:
First, an ifBlock
with a nested LOGIC
block. The LOGIC observation is created
so ifBlock
is not rerun over and over if show
were to change from 1 to 2 to 3, etc.
var ifBlock = new Observation( () => {
var LOGIC = new Observation(() => { return !!vm.show })
if(LOGIC.get()) {
return options.fn()
} else {
return options.inverse();
}
})
Second, options.fn
(and options.inverse) are compiled to something like:
option.fn = function(){
foo = new Observation(() => vm.foo , {canRecordObservation: false});
return frag("<div/>", live.text(textNode, foo))
}
Note the canRecordObservation
on the foo
observation. This is used to prevent ifBlock
from re-running if foo
changes. If foo
changes, live.text
handles updating the DOM itself. There's no need to rerun ifBlock
.
Proposal
The idea is to:
- make an observation see any observables created within its function and to be able to tear them down automatically when the function returns.
- schedule any child observations "after" the parent observation, allowing the parent to run first.
In the example above, if ifBlock
were to re-run its function, both LOGIC
and foo
should be torn down.
By torn down
we mean all activity should stop. Any handlers listening to those observables should be removed (watch out for handlers bound with .listenTo()
). Also those observables should not be binding on their dependencies. Currently, I believe can-event-queues/value
supports calling .off()
without arguments to tear down any handlers. This should probably be formalized, possibly as a canReflect.stop()
(which could also work for Map and List types).
Finally, the child-parent relationship needs to be established. I think part of this can happen with expansion of can-observation-recorder
. An observation record could contain a set of createdDependencies
:
createdDependencies: new Set()
I think child observables can register themselves with:
ObservationRecorder.created( observable )
When can-observation
updates its value, it can go through createdDependencies
and call canReflect.stop(observable)
on each observable.
Other
- As observation's will take on their "parent's" priority
+ 1
, Infinity + 1
is still Infinity
. This might mean resuming the default priority of 0.