mirror of https://github.com/vuejs/vue.git
save and throw async stack trace in debug mode
This commit is contained in:
parent
da315f840b
commit
b9d8ad37ce
|
|
@ -73,15 +73,12 @@ exports.$delete = function (key) {
|
||||||
|
|
||||||
exports.$watch = function (exp, cb, options) {
|
exports.$watch = function (exp, cb, options) {
|
||||||
var vm = this
|
var vm = this
|
||||||
var wrappedCb = function (val, oldVal) {
|
var watcher = new Watcher(vm, exp, cb, {
|
||||||
cb.call(vm, val, oldVal)
|
|
||||||
}
|
|
||||||
var watcher = new Watcher(vm, exp, wrappedCb, {
|
|
||||||
deep: options && options.deep,
|
deep: options && options.deep,
|
||||||
user: !options || options.user !== false
|
user: !options || options.user !== false
|
||||||
})
|
})
|
||||||
if (options && options.immediate) {
|
if (options && options.immediate) {
|
||||||
wrappedCb(watcher.value)
|
cb.call(vm, watcher.value)
|
||||||
}
|
}
|
||||||
return function unwatchFn () {
|
return function unwatchFn () {
|
||||||
watcher.teardown()
|
watcher.teardown()
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@ var uid = 0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Watcher (vm, expOrFn, cb, options) {
|
function Watcher (vm, expOrFn, cb, options) {
|
||||||
|
// mix in options
|
||||||
|
if (options) {
|
||||||
|
_.extend(this, options)
|
||||||
|
}
|
||||||
var isFn = typeof expOrFn === 'function'
|
var isFn = typeof expOrFn === 'function'
|
||||||
this.vm = vm
|
this.vm = vm
|
||||||
vm._watchers.push(this)
|
vm._watchers.push(this)
|
||||||
|
|
@ -32,23 +36,16 @@ function Watcher (vm, expOrFn, cb, options) {
|
||||||
this.cb = cb
|
this.cb = cb
|
||||||
this.id = ++uid // uid for batching
|
this.id = ++uid // uid for batching
|
||||||
this.active = true
|
this.active = true
|
||||||
options = options || {}
|
this.dirty = this.lazy // for lazy watchers
|
||||||
this.deep = !!options.deep
|
|
||||||
this.user = !!options.user
|
|
||||||
this.twoWay = !!options.twoWay
|
|
||||||
this.sync = !!options.sync
|
|
||||||
this.lazy = !!options.lazy
|
|
||||||
this.dirty = this.lazy
|
|
||||||
this.filters = options.filters
|
|
||||||
this.preProcess = options.preProcess
|
|
||||||
this.deps = []
|
this.deps = []
|
||||||
this.newDeps = null
|
this.newDeps = null
|
||||||
|
this.prevError = null // for async error stacks
|
||||||
// parse expression for getter/setter
|
// parse expression for getter/setter
|
||||||
if (isFn) {
|
if (isFn) {
|
||||||
this.getter = expOrFn
|
this.getter = expOrFn
|
||||||
this.setter = undefined
|
this.setter = undefined
|
||||||
} else {
|
} else {
|
||||||
var res = expParser.parse(expOrFn, options.twoWay)
|
var res = expParser.parse(expOrFn, this.twoWay)
|
||||||
this.getter = res.get
|
this.getter = res.get
|
||||||
this.setter = res.set
|
this.setter = res.set
|
||||||
}
|
}
|
||||||
|
|
@ -196,6 +193,11 @@ p.update = function (shallow) {
|
||||||
: false
|
: false
|
||||||
: !!shallow
|
: !!shallow
|
||||||
this.queued = true
|
this.queued = true
|
||||||
|
// record before-push error stack in debug mode
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (process.env.NODE_ENV !== 'production' && config.debug) {
|
||||||
|
this.prevError = new Error('[vue] async stack trace')
|
||||||
|
}
|
||||||
batcher.push(this)
|
batcher.push(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -216,9 +218,28 @@ p.run = function () {
|
||||||
// non-shallow update (caused by a vm digest).
|
// non-shallow update (caused by a vm digest).
|
||||||
((_.isArray(value) || this.deep) && !this.shallow)
|
((_.isArray(value) || this.deep) && !this.shallow)
|
||||||
) {
|
) {
|
||||||
|
// set new value
|
||||||
var oldValue = this.value
|
var oldValue = this.value
|
||||||
this.value = value
|
this.value = value
|
||||||
this.cb(value, oldValue)
|
// in debug + async mode, when a watcher callbacks
|
||||||
|
// throws, we also throw the saved before-push error
|
||||||
|
// so the full cross-tick stack trace is available.
|
||||||
|
var prevError = this.prevError
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (process.env.NODE_ENV !== 'production' &&
|
||||||
|
config.debug && prevError) {
|
||||||
|
this.prevError = null
|
||||||
|
try {
|
||||||
|
this.cb.call(this.vm, value, oldValue)
|
||||||
|
} catch (e) {
|
||||||
|
_.nextTick(function () {
|
||||||
|
throw prevError
|
||||||
|
}, 0)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.cb.call(this.vm, value, oldValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.queued = this.shallow = false
|
this.queued = this.shallow = false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ describe('Data API', function () {
|
||||||
var unwatch = vm.$watch('a + b.c', spy, {
|
var unwatch = vm.$watch('a + b.c', spy, {
|
||||||
immediate: true
|
immediate: true
|
||||||
})
|
})
|
||||||
expect(spy).toHaveBeenCalledWith(3, undefined)
|
expect(spy).toHaveBeenCalledWith(3)
|
||||||
vm.a = 2
|
vm.a = 2
|
||||||
nextTick(function () {
|
nextTick(function () {
|
||||||
expect(spy).toHaveBeenCalledWith(4, 3)
|
expect(spy).toHaveBeenCalledWith(4, 3)
|
||||||
|
|
@ -112,7 +112,7 @@ describe('Data API', function () {
|
||||||
var unwatch = vm.$watch(function () {
|
var unwatch = vm.$watch(function () {
|
||||||
return this.a + this.b.c
|
return this.a + this.b.c
|
||||||
}, spy, { immediate: true })
|
}, spy, { immediate: true })
|
||||||
expect(spy).toHaveBeenCalledWith(3, undefined)
|
expect(spy).toHaveBeenCalledWith(3)
|
||||||
vm.a = 2
|
vm.a = 2
|
||||||
nextTick(function () {
|
nextTick(function () {
|
||||||
expect(spy).toHaveBeenCalledWith(4, 3)
|
expect(spy).toHaveBeenCalledWith(4, 3)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue