Files: c01dae98743153d400531ac256fb74b5ca35138e / computed.js
2171 bytesRaw
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 |
4 | |
5 | var resolve = require('./resolve') |
6 | |
7 | module.exports = computed |
8 | |
9 | function computed (observables, lambda) { |
10 | var values = [] |
11 | var releases = [] |
12 | var computedValue = null |
13 | var live = false |
14 | var lazy = false |
15 | var listeners = [] |
16 | |
17 | var result = function (listener) { |
18 | if (!listener) { |
19 | return getValue() |
20 | } |
21 | |
22 | if (typeof listener !== 'function') { |
23 | throw new Error('Listeners must be functions.') |
24 | } |
25 | |
26 | listeners.push(listener) |
27 | listen() |
28 | |
29 | return function remove () { |
30 | for (var i = 0, len = listeners.length; i < len; i++) { |
31 | if (listeners[i] === listener) { |
32 | listeners.splice(i, 1) |
33 | break |
34 | } |
35 | } |
36 | if (!listeners.length) { |
37 | unlisten() |
38 | } |
39 | } |
40 | } |
41 | |
42 | return result |
43 | |
44 | // scoped |
45 | |
46 | function listen () { |
47 | if (!live) { |
48 | for (var i = 0, len = observables.length; i < len; i++) { |
49 | if (typeof observables[i] === 'function') { |
50 | releases.push(observables[i](onUpdate)) |
51 | } |
52 | } |
53 | live = true |
54 | lazy = true |
55 | } |
56 | } |
57 | |
58 | function unlisten () { |
59 | if (live) { |
60 | live = false |
61 | while (releases.length) { |
62 | releases.pop()() |
63 | } |
64 | } |
65 | } |
66 | |
67 | function update () { |
68 | var changed = false |
69 | for (var i = 0, len = observables.length; i < len; i++) { |
70 | var newValue = resolve(observables[i]) |
71 | if (newValue !== values[i] || typeof newValue === 'object') { |
72 | changed = true |
73 | values[i] = newValue |
74 | } |
75 | } |
76 | |
77 | if (changed) { |
78 | var newComputedValue = lambda.apply(null, values) |
79 | if (newComputedValue !== computedValue || typeof newComputedValue === 'object') { |
80 | computedValue = newComputedValue |
81 | return true |
82 | } |
83 | } |
84 | return false |
85 | } |
86 | |
87 | function onUpdate () { |
88 | if (update()) { |
89 | for (var i = 0, len = listeners.length; i < len; i++) { |
90 | listeners[i](computedValue) |
91 | } |
92 | } |
93 | } |
94 | |
95 | function getValue () { |
96 | if (!live || lazy) { |
97 | lazy = false |
98 | update() |
99 | } |
100 | return computedValue |
101 | } |
102 | } |
103 |
Built with git-ssb-web