Skip to content

Commit b9d8ad3

Browse files
committed
save and throw async stack trace in debug mode
1 parent da315f8 commit b9d8ad3

File tree

3 files changed

+36
-18
lines changed

3 files changed

+36
-18
lines changed

src/api/data.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,12 @@ exports.$delete = function (key) {
7373

7474
exports.$watch = function (exp, cb, options) {
7575
var vm = this
76-
var wrappedCb = function (val, oldVal) {
77-
cb.call(vm, val, oldVal)
78-
}
79-
var watcher = new Watcher(vm, exp, wrappedCb, {
76+
var watcher = new Watcher(vm, exp, cb, {
8077
deep: options && options.deep,
8178
user: !options || options.user !== false
8279
})
8380
if (options && options.immediate) {
84-
wrappedCb(watcher.value)
81+
cb.call(vm, watcher.value)
8582
}
8683
return function unwatchFn () {
8784
watcher.teardown()

src/watcher.js

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,30 +25,27 @@ var uid = 0
2525
*/
2626

2727
function Watcher (vm, expOrFn, cb, options) {
28+
// mix in options
29+
if (options) {
30+
_.extend(this, options)
31+
}
2832
var isFn = typeof expOrFn === 'function'
2933
this.vm = vm
3034
vm._watchers.push(this)
3135
this.expression = isFn ? expOrFn.toString() : expOrFn
3236
this.cb = cb
3337
this.id = ++uid // uid for batching
3438
this.active = true
35-
options = options || {}
36-
this.deep = !!options.deep
37-
this.user = !!options.user
38-
this.twoWay = !!options.twoWay
39-
this.sync = !!options.sync
40-
this.lazy = !!options.lazy
41-
this.dirty = this.lazy
42-
this.filters = options.filters
43-
this.preProcess = options.preProcess
39+
this.dirty = this.lazy // for lazy watchers
4440
this.deps = []
4541
this.newDeps = null
42+
this.prevError = null // for async error stacks
4643
// parse expression for getter/setter
4744
if (isFn) {
4845
this.getter = expOrFn
4946
this.setter = undefined
5047
} else {
51-
var res = expParser.parse(expOrFn, options.twoWay)
48+
var res = expParser.parse(expOrFn, this.twoWay)
5249
this.getter = res.get
5350
this.setter = res.set
5451
}
@@ -196,6 +193,11 @@ p.update = function (shallow) {
196193
: false
197194
: !!shallow
198195
this.queued = true
196+
// record before-push error stack in debug mode
197+
/* istanbul ignore if */
198+
if (process.env.NODE_ENV !== 'production' && config.debug) {
199+
this.prevError = new Error('[vue] async stack trace')
200+
}
199201
batcher.push(this)
200202
}
201203
}
@@ -216,9 +218,28 @@ p.run = function () {
216218
// non-shallow update (caused by a vm digest).
217219
((_.isArray(value) || this.deep) && !this.shallow)
218220
) {
221+
// set new value
219222
var oldValue = this.value
220223
this.value = value
221-
this.cb(value, oldValue)
224+
// in debug + async mode, when a watcher callbacks
225+
// throws, we also throw the saved before-push error
226+
// so the full cross-tick stack trace is available.
227+
var prevError = this.prevError
228+
/* istanbul ignore if */
229+
if (process.env.NODE_ENV !== 'production' &&
230+
config.debug && prevError) {
231+
this.prevError = null
232+
try {
233+
this.cb.call(this.vm, value, oldValue)
234+
} catch (e) {
235+
_.nextTick(function () {
236+
throw prevError
237+
}, 0)
238+
throw e
239+
}
240+
} else {
241+
this.cb.call(this.vm, value, oldValue)
242+
}
222243
}
223244
this.queued = this.shallow = false
224245
}

test/unit/specs/api/data_spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ describe('Data API', function () {
9292
var unwatch = vm.$watch('a + b.c', spy, {
9393
immediate: true
9494
})
95-
expect(spy).toHaveBeenCalledWith(3, undefined)
95+
expect(spy).toHaveBeenCalledWith(3)
9696
vm.a = 2
9797
nextTick(function () {
9898
expect(spy).toHaveBeenCalledWith(4, 3)
@@ -112,7 +112,7 @@ describe('Data API', function () {
112112
var unwatch = vm.$watch(function () {
113113
return this.a + this.b.c
114114
}, spy, { immediate: true })
115-
expect(spy).toHaveBeenCalledWith(3, undefined)
115+
expect(spy).toHaveBeenCalledWith(3)
116116
vm.a = 2
117117
nextTick(function () {
118118
expect(spy).toHaveBeenCalledWith(4, 3)

0 commit comments

Comments
 (0)