git ssb

1+

Matt McKegg / mutant



Commit ef9e5ab9d31b22070e49efa9d5db1f9b8f20b572

computed: remove lazy state, instead non-live `get` temporarily goes live

to handle some weird race conditions caused by out of cycle updates
and fix cyclical loop caused by 52a53f6c954527bd2ff1b45d18bbf6679ef83038
Matt McKegg committed on 6/14/2017, 7:05:03 AM
Parent: 4785d5ea1d640ca8bd46c416557dde4dea903fc7

Files changed

computed.jschanged
test/computed.jsadded
computed.jsView
@@ -32,9 +32,8 @@
3232 this.outputValue = null
3333 this.inner = null
3434 this.updating = false
3535 this.live = false
36- this.lazy = false
3736 this.initialized = false
3837 this.listeners = []
3938 this.observables = observables
4039 this.lambda = lambda
@@ -46,8 +45,9 @@
4645
4746 this.context = opts && opts.context || {}
4847 this.boundOnUpdate = this.onUpdate.bind(this)
4948 this.boundUpdateNow = this.updateNow.bind(this)
49 + this.boundUnlisten = this.unlisten.bind(this)
5050 }
5151
5252 ProtoComputed.prototype = {
5353 MutantComputed: function (listener) {
@@ -85,9 +85,9 @@
8585 if (this.inner) {
8686 this.releaseInner = this.inner(this.onInnerUpdate.bind(this, this.inner))
8787 }
8888 this.live = true
89- this.lazy = true
89 + this.update()
9090
9191 if (this.opts && this.opts.onListen) {
9292 var release = this.opts.onListen()
9393 if (typeof release === 'function') {
@@ -96,9 +96,9 @@
9696 }
9797 }
9898 },
9999 unlisten: function () {
100- if (this.live) {
100 + if (this.live && !this.listeners.length) {
101101 this.live = false
102102
103103 if (this.releaseInner) {
104104 this.releaseInner()
@@ -184,21 +184,13 @@
184184 this.broadcast()
185185 }
186186 },
187187 getValue: function () {
188- var wasLazy = this.live && this.lazy
189- if (!this.live || this.lazy || this.updating) {
190- this.lazy = false
191- if (this.opts && this.opts.nextTick && this.live && this.lazy) {
192- this.onUpdate() // use cached value to make more responsive
193- } else {
194- if (this.update() && wasLazy) {
195- this.broadcast()
196- }
197- }
198- if (this.inner) {
199- this.outputValue = resolve(this.inner)
200- }
188 + if (!this.updating && !this.live) {
189 + // temporarily become live to watch for changes until next cycle to stop
190 + // potential double refresh and handle weird race conditions
191 + this.listen() // triggers update
192 + setImmediate(this.boundUnlisten) // only runs if no listeners have been added
201193 }
202194 return this.outputValue
203195 },
204196 broadcast: function () {
@@ -211,20 +203,18 @@
211203 }
212204
213205 function extendedComputed (observables, update) {
214206 var live = false
215- var lazy = false
216207
217208 var instance = computed(observables, function () {
218209 return update()
219210 }, {
220- onListen: function () { live = lazy = true },
211 + onListen: function () { live = true },
221212 onUnlisten: function () { live = false }
222213 })
223214
224215 instance.checkUpdated = function () {
225- if (!live || lazy) {
226- lazy = false
216 + if (!live) {
227217 update()
228218 }
229219 }
230220
test/computed.jsView
@@ -1,0 +1,47 @@
1 +require('setimmediate')
2 +var test = require('tape')
3 +
4 +var computed = require('../computed')
5 +var resolve = require('../resolve')
6 +var Value = require('../value')
7 +
8 +test('computed get accessor', function(t) {
9 + var value = Value(1)
10 + var obs = computed(value, x => x * 100)
11 + t.equal(resolve(obs), 100)
12 + value.set(2)
13 + t.equal(resolve(obs), 200)
14 + t.end()
15 +})
16 +
17 +test('computed lazy watch', function(t) {
18 + var value = Value(1)
19 + var obs = computed(value, x => x * 100)
20 + t.equal(resolve(obs), 100)
21 +
22 + var observedValues = []
23 + obs(x => observedValues.push(x))
24 + value.set(2)
25 + t.deepEqual(observedValues, [200])
26 +
27 + t.end()
28 +})
29 +
30 +test('computed lazy watch with `get` race condition', function(t) {
31 + var value = Value(1)
32 + var final = Value()
33 +
34 + var obs = computed(value, x => x * 100)
35 + t.equal(resolve(obs), 100)
36 +
37 + value(x => {
38 + resolve(obs) // resolve obs inside of observer
39 + })
40 +
41 + obs(final.set)
42 +
43 + value.set(2)
44 +
45 + t.deepEqual(resolve(final), 200)
46 + t.end()
47 +})

Built with git-ssb-web