Commit 2244524e466413910788cad98baa61df4f340866
computed: resolve and broadcast inner value if observable
Matt McKegg committed on 7/15/2016, 3:04:19 AMParent: ec39f72902c3a64aa9841e339bd53cf60182953c
Files changed
computed.js | changed |
computed.js | |||
---|---|---|---|
@@ -1,18 +1,30 @@ | |||
1 | 1 … | /* A lazy binding take on computed */ | |
2 | -// doesn't start watching observables until itself is watched, and then releases if unwatched | ||
3 | -// avoids memory/watcher leakage | ||
2 … | +// - doesn't start watching observables until itself is watched, and then releases if unwatched | ||
3 … | +// - avoids memory/watcher leakage | ||
4 … | +// - attaches to inner observables if these are returned from value | ||
5 … | +// - doesn't broadcast if value is same as last value (and is `value type` or observable, can't make assuptions about reference types) | ||
4 | 6 … | ||
5 | 7 … | var resolve = require('./resolve') | |
8 … | +var isObservable = require('./is-observable') | ||
6 | 9 … | ||
7 | 10 … | module.exports = computed | |
8 | 11 … | ||
9 | 12 … | function computed (observables, lambda) { | |
13 … | + if (!Array.isArray(observables)) { | ||
14 … | + observables = [observables] | ||
15 … | + } | ||
16 … | + | ||
10 | 17 … | var values = [] | |
11 | 18 … | var releases = [] | |
12 | 19 … | var computedValue = null | |
20 … | + | ||
21 … | + var inner = null | ||
22 … | + var releaseInner = null | ||
23 … | + | ||
13 | 24 … | var live = false | |
14 | 25 … | var lazy = false | |
26 … | + var initialized = false | ||
15 | 27 … | var listeners = [] | |
16 | 28 … | ||
17 | 29 … | var result = function (listener) { | |
18 | 30 … | if (!listener) { | |
@@ -49,16 +61,25 @@ | |||
49 | 61 … | if (typeof observables[i] === 'function') { | |
50 | 62 … | releases.push(observables[i](onUpdate)) | |
51 | 63 … | } | |
52 | 64 … | } | |
65 … | + if (inner) { | ||
66 … | + releaseInner = inner(onInnerUpdate) | ||
67 … | + } | ||
53 | 68 … | live = true | |
54 | 69 … | lazy = true | |
55 | 70 … | } | |
56 | 71 … | } | |
57 | 72 … | ||
58 | 73 … | function unlisten () { | |
59 | 74 … | if (live) { | |
60 | 75 … | live = false | |
76 … | + | ||
77 … | + if (releaseInner) { | ||
78 … | + releaseInner() | ||
79 … | + releaseInner = null | ||
80 … | + } | ||
81 … | + | ||
61 | 82 … | while (releases.length) { | |
62 | 83 … | releases.pop()() | |
63 | 84 … | } | |
64 | 85 … | } | |
@@ -73,18 +94,42 @@ | |||
73 | 94 … | values[i] = newValue | |
74 | 95 … | } | |
75 | 96 … | } | |
76 | 97 … | ||
77 | - if (changed) { | ||
98 … | + if (changed || !initialized) { | ||
99 … | + initialized = true | ||
78 | 100 … | var newComputedValue = lambda.apply(null, values) | |
79 | - if (newComputedValue !== computedValue || typeof newComputedValue === 'object') { | ||
80 | - computedValue = newComputedValue | ||
101 … | + if (newComputedValue !== computedValue || (typeof newComputedValue === 'object' && !isObservable(newComputedValue))) { | ||
102 … | + if (releaseInner) { | ||
103 … | + releaseInner() | ||
104 … | + inner = releaseInner = null | ||
105 … | + } | ||
106 … | + | ||
107 … | + if (isObservable(newComputedValue)) { | ||
108 … | + // handle returning observable from computed | ||
109 … | + computedValue = newComputedValue() | ||
110 … | + inner = newComputedValue | ||
111 … | + if (live) { | ||
112 … | + releaseInner = inner(onInnerUpdate) | ||
113 … | + } | ||
114 … | + } else { | ||
115 … | + computedValue = newComputedValue | ||
116 … | + } | ||
81 | 117 … | return true | |
82 | 118 … | } | |
83 | 119 … | } | |
84 | 120 … | return false | |
85 | 121 … | } | |
86 | 122 … | ||
123 … | + function onInnerUpdate (value) { | ||
124 … | + if (value !== computedValue || typeof newComputedValue === 'object') { | ||
125 … | + computedValue = value | ||
126 … | + for (var i = 0, len = listeners.length; i < len; i++) { | ||
127 … | + listeners[i](computedValue) | ||
128 … | + } | ||
129 … | + } | ||
130 … | + } | ||
131 … | + | ||
87 | 132 … | function onUpdate () { | |
88 | 133 … | if (update()) { | |
89 | 134 … | for (var i = 0, len = listeners.length; i < len; i++) { | |
90 | 135 … | listeners[i](computedValue) |
Built with git-ssb-web