Files: 9a45ee19f015307308d964ffa52965fe95ed8ad0 / lib / lazy-watcher.js
2486 bytesRaw
1 | var onceIdle = require('../once-idle') |
2 | |
3 | module.exports = function (update, onBind, onUnbind) { |
4 | var lazy = false |
5 | var context = this |
6 | var updating = false |
7 | |
8 | var obj = { |
9 | live: false, |
10 | nextTick: false, |
11 | idle: false, |
12 | suspended: false, |
13 | update: update, |
14 | value: null, |
15 | listeners: [], |
16 | |
17 | broadcast: function () { |
18 | if (obj.nextTick) { |
19 | if (!updating) { |
20 | updating = true |
21 | setImmediate(broadcast) |
22 | } |
23 | } else { |
24 | broadcast() |
25 | } |
26 | }, |
27 | |
28 | transaction: function (value, cb) { |
29 | var originalValue = obj.suspended |
30 | obj.suspended = true |
31 | cb(value) |
32 | obj.suspended = originalValue |
33 | obj.broadcast() |
34 | }, |
35 | |
36 | onUpdate: function () { |
37 | if (obj.idle) { |
38 | if (!updating) { |
39 | updating = true |
40 | onceIdle(obj.updateAndBroadcast) |
41 | } |
42 | } else if (obj.nextTick) { |
43 | if (!updating) { |
44 | updating = true |
45 | setImmediate(obj.updateAndBroadcast) |
46 | } |
47 | } else { |
48 | obj.updateAndBroadcast() |
49 | } |
50 | }, |
51 | |
52 | updateAndBroadcast: function () { |
53 | updating = false |
54 | if (update.call(context)) { |
55 | broadcast() |
56 | } |
57 | }, |
58 | |
59 | checkUpdated: function () { |
60 | if (!obj.live || lazy || updating) { |
61 | lazy = false |
62 | if (obj.nextTick && obj.live && lazy) { |
63 | obj.onUpdate() // use cached value to make more responsive |
64 | } else { |
65 | update.apply(context) |
66 | } |
67 | } |
68 | }, |
69 | |
70 | getValue: function () { |
71 | obj.checkUpdated.apply(context) |
72 | return obj.value |
73 | }, |
74 | |
75 | addListener: function (listener) { |
76 | if (typeof listener !== 'function') { |
77 | throw new Error('Listeners must be functions.') |
78 | } |
79 | |
80 | obj.listeners.push(listener) |
81 | |
82 | if (!obj.live) { |
83 | obj.live = true |
84 | lazy = true |
85 | onBind.apply(context) |
86 | } |
87 | |
88 | return function release () { |
89 | for (var i = 0, len = obj.listeners.length; i < len; i++) { |
90 | if (obj.listeners[i] === listener) { |
91 | obj.listeners.splice(i, 1) |
92 | break |
93 | } |
94 | } |
95 | if (!obj.listeners.length && obj.live) { |
96 | obj.live = false |
97 | onUnbind.apply(context) |
98 | } |
99 | } |
100 | } |
101 | } |
102 | |
103 | return obj |
104 | |
105 | // scoped |
106 | |
107 | function broadcast () { |
108 | if (!obj.suspended) { |
109 | var cachedListeners = obj.listeners.slice(0) |
110 | for (var i = 0, len = cachedListeners.length; i < len; i++) { |
111 | cachedListeners[i](obj.value) |
112 | } |
113 | } |
114 | } |
115 | } |
116 |
Built with git-ssb-web