Skip to content

Instantly share code, notes, and snippets.

@craigyk
Created February 14, 2012 19:21
Show Gist options
  • Save craigyk/1829421 to your computer and use it in GitHub Desktop.
Save craigyk/1829421 to your computer and use it in GitHub Desktop.
JS computed and observable variables
frames = []
addFrame = (frame) -> frames.push frame || []
addToStack = (obs) -> if frames.length > 0 then frames[frames.length-1].push obs
mergeFrame = (obs) -> if frames.length > 0 then frames[frames.length-1] = frames[frames.length-1].concat obs
popFrame = ->
popped = unique frames.pop()
mergeFrame popped
return popped
unique = (frame) ->
set = {}
nframe = []
for obs in frame
if obs.id not of set
set[obs.id] = true
nframe.push obs
return nframe
notify = (bindings,value) ->
newbindings = []
for call in bindings
if call value
newbindings.push call
return newbindings
obsids = 0
computed = (tocompute) ->
watched = []
cached = null
dirty = true
evaluate = ->
if dirty
dirty = false
addFrame()
value = tocompute()
watched = popFrame()
if value != cached
for obs in watched
obs.bind -> dirty = true; false;
cached = value
else mergeFrame watched
return cached
evaluate.bind = (call) -> obs.bind(-> call evaluate()) for obs in watched
evaluate.tocompute = tocompute
evaluate()
return evaluate
observable = (value) ->
if value.id
return value
cached = value
bindings = []
evaluate = (value) ->
addToStack evaluate
if value? and value != cached
cached = value
bindings = notify bindings, value
return cached
evaluate.id = obsids++
evaluate.bind = (call) -> bindings.push call
return evaluate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment