diff --git a/src/core/instance/state.js b/src/core/instance/state.js index 326f7f36bf7..238bb4761ee 100644 --- a/src/core/instance/state.js +++ b/src/core/instance/state.js @@ -346,7 +346,11 @@ export function stateMixin (Vue: Class) { options.user = true const watcher = new Watcher(vm, expOrFn, cb, options) if (options.immediate) { - cb.call(vm, watcher.value) + try { + cb.call(vm, watcher.value) + } catch (error) { + handleError(error, vm, `callback for immediate watcher "${watcher.expression}"`) + } } return function unwatchFn () { watcher.teardown() diff --git a/test/unit/features/error-handling.spec.js b/test/unit/features/error-handling.spec.js index 217bb72721a..df52b76efc6 100644 --- a/test/unit/features/error-handling.spec.js +++ b/test/unit/features/error-handling.spec.js @@ -92,6 +92,16 @@ describe('Error handling', () => { }).then(done) }) + it('should recover from errors in user immediate watcher callback', done => { + const vm = createTestInstance(components.userImmediateWatcherCallback) + waitForUpdate(() => { + expect(`Error in callback for immediate watcher "n"`).toHaveBeenWarned() + expect(`Error: userImmediateWatcherCallback error`).toHaveBeenWarned() + }).thenWaitFor(next => { + assertBothInstancesActive(vm).end(next) + }).then(done) + }) + it('config.errorHandler should capture render errors', done => { const spy = Vue.config.errorHandler = jasmine.createSpy('errorHandler') const vm = createTestInstance(components.render) @@ -234,6 +244,21 @@ function createErrorTestComponents () { } } + components.userImmediateWatcherCallback = { + props: ['n'], + watch: { + n: { + immediate: true, + handler () { + throw new Error('userImmediateWatcherCallback error') + } + } + }, + render (h) { + return h('div', this.n) + } + } + // event errors components.event = { beforeCreate () {