Skip to content

Commit 7b1c2f4

Browse files
committed
avoid false watcher triggering on deep/Array watchers during digest (fix #1014)
1 parent a1b9da8 commit 7b1c2f4

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

src/instance/scope.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ exports._unproxy = function (key) {
166166
exports._digest = function () {
167167
var i = this._watchers.length
168168
while (i--) {
169-
this._watchers[i].update()
169+
this._watchers[i].update(true) // shallow updates
170170
}
171171
var children = this.$children
172172
i = children.length

src/watcher.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ function Watcher (vm, expOrFn, cb, options) {
4848
this.setter = res.set
4949
}
5050
this.value = this.get()
51+
// state for avoiding false triggers for deep and Array
52+
// watchers during vm._digest()
53+
this.queued = this.shallow = false
5154
}
5255

5356
var p = Watcher.prototype
@@ -161,12 +164,22 @@ p.afterGet = function () {
161164
/**
162165
* Subscriber interface.
163166
* Will be called when a dependency changes.
167+
*
168+
* @param {Boolean} shallow
164169
*/
165170

166-
p.update = function () {
171+
p.update = function (shallow) {
167172
if (!config.async) {
168173
this.run()
169174
} else {
175+
// if queued, only overwrite shallow with non-shallow,
176+
// but not the other way around.
177+
this.shallow = this.queued
178+
? shallow
179+
? this.shallow
180+
: false
181+
: !!shallow
182+
this.queued = true
170183
batcher.push(this)
171184
}
172185
}
@@ -181,13 +194,17 @@ p.run = function () {
181194
var value = this.get()
182195
if (
183196
value !== this.value ||
184-
_.isArray(value) ||
185-
this.deep
197+
// Deep watchers and Array watchers should fire even
198+
// when the value is the same, because the value may
199+
// have mutated; but only do so if this is a
200+
// non-shallow update (caused by a vm digest).
201+
((_.isArray(value) || this.deep) && !this.shallow)
186202
) {
187203
var oldValue = this.value
188204
this.value = value
189205
this.cb(value, oldValue)
190206
}
207+
this.queued = this.shallow = false
191208
}
192209
}
193210

test/unit/specs/misc_spec.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,49 @@ describe('Misc', function () {
176176
})
177177
})
178178

179+
it('should not trigger deep/Array watchers when digesting', function (done) {
180+
var spy1 = jasmine.createSpy('deep')
181+
var spy2 = jasmine.createSpy('Array')
182+
var spy3 = jasmine.createSpy('test')
183+
var spy4 = jasmine.createSpy('deep-mutated')
184+
var vm = new Vue({
185+
el: 'body',
186+
data: {
187+
obj: {},
188+
arr: [],
189+
obj2: {}
190+
},
191+
watch: {
192+
obj: {
193+
handler: spy1,
194+
deep: true
195+
},
196+
arr: spy2,
197+
// if the watcher is watching the added value,
198+
// it should still trigger properly
199+
test: {
200+
handler: spy3,
201+
deep: true
202+
},
203+
// if the object is in fact mutated, it should
204+
// still trigger.
205+
obj2: {
206+
handler: spy4,
207+
deep: true
208+
}
209+
}
210+
})
211+
var test = []
212+
var obj2 = vm.obj2
213+
vm.$add('test', test)
214+
obj2.$add('test', 123)
215+
Vue.nextTick(function () {
216+
expect(spy1).not.toHaveBeenCalled()
217+
expect(spy2).not.toHaveBeenCalled()
218+
expect(spy3).toHaveBeenCalledWith(test, undefined)
219+
expect(spy4).toHaveBeenCalledWith(obj2, obj2)
220+
done()
221+
})
222+
})
223+
179224
})

0 commit comments

Comments
 (0)