Skip to content

Commit 086b5b6

Browse files
authored
Merge pull request #1 from coldino/extended-async-handling
Add handling for v-on normal+async errors (vuejs#6953)
2 parents 5309833 + 3fa6b02 commit 086b5b6

File tree

3 files changed

+49
-8
lines changed

3 files changed

+49
-8
lines changed

src/core/util/error.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ export function handleError (err: Error, vm: any, info: string) {
2424
globalHandleError(err, vm, info)
2525
}
2626

27-
export function handlePromiseError(value: any, vm: any, info: string) {
28-
// if value is promise, handle it
29-
if (value && typeof value.catch === 'function') {
27+
export function handlePromiseError (value: any, vm: any, info: string) {
28+
// if value is promise, handle it (a promise must have a then function)
29+
if (value && typeof value.then === 'function' && typeof value.catch === 'function') {
3030
value.catch(e => handleError(e, vm, info))
3131
}
3232
}

src/core/vdom/helpers/update-listeners.js

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* @flow */
22

3-
import { warn } from 'core/util/index'
3+
import { warn, handleError, handlePromiseError } from 'core/util/index'
44
import { cached, isUndef, isPlainObject } from 'shared/util'
55

66
const normalizeEvent = cached((name: string): {
@@ -25,17 +25,29 @@ const normalizeEvent = cached((name: string): {
2525
}
2626
})
2727

28-
export function createFnInvoker (fns: Function | Array<Function>): Function {
28+
export function createFnInvoker (fns: Function | Array<Function>, vm: ?Component): Function {
2929
function invoker () {
3030
const fns = invoker.fns
3131
if (Array.isArray(fns)) {
3232
const cloned = fns.slice()
3333
for (let i = 0; i < cloned.length; i++) {
34-
cloned[i].apply(null, arguments)
34+
try {
35+
const result = cloned[i].apply(null, arguments)
36+
handlePromiseError(result, vm, 'v-on async')
37+
} catch (e) {
38+
handleError(e, vm, 'v-on')
39+
}
3540
}
3641
} else {
3742
// return handler return value for single handlers
38-
return fns.apply(null, arguments)
43+
let result
44+
try {
45+
result = fns.apply(null, arguments)
46+
handlePromiseError(result, vm, 'v-on async')
47+
} catch (e) {
48+
handleError(e, vm, 'v-on')
49+
}
50+
return result
3951
}
4052
}
4153
invoker.fns = fns
@@ -66,7 +78,7 @@ export function updateListeners (
6678
)
6779
} else if (isUndef(old)) {
6880
if (isUndef(cur.fns)) {
69-
cur = on[name] = createFnInvoker(cur)
81+
cur = on[name] = createFnInvoker(cur, vm)
7082
}
7183
add(event.name, cur, event.once, event.capture, event.passive, event.params)
7284
} else if (cur !== old) {

test/unit/features/error-handling.spec.js

+29
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,35 @@ describe('Error handling', () => {
188188
expect(vm.$el.textContent).toContain('error in render')
189189
Vue.config.errorHandler = null
190190
})
191+
192+
it('should capture and recover from v-on errors', () => {
193+
const spy = Vue.config.errorHandler = jasmine.createSpy('errorHandler')
194+
const err1 = new Error('clickbork')
195+
const vm = new Vue({
196+
template: '<div v-on:click="bork"></div>',
197+
methods: { bork: function () { throw err1 } }
198+
}).$mount()
199+
triggerEvent(vm.$el, 'click')
200+
expect(spy.calls.count()).toBe(1)
201+
expect(spy).toHaveBeenCalledWith(err1, vm, 'v-on')
202+
Vue.config.errorHandler = null
203+
})
204+
205+
it('should capture and recover from v-on async errors', (done) => {
206+
const spy = Vue.config.errorHandler = jasmine.createSpy('errorHandler')
207+
const err1 = new Error('clickbork')
208+
const vm = new Vue({
209+
template: '<div v-on:click="bork"></div>',
210+
methods: { bork: function () { return new Promise(function (_resolve, reject) { reject(err1) }) } }
211+
}).$mount()
212+
triggerEvent(vm.$el, 'click')
213+
Vue.nextTick(() => {
214+
expect(spy.calls.count()).toBe(1)
215+
expect(spy).toHaveBeenCalledWith(err1, vm, 'v-on async')
216+
Vue.config.errorHandler = null
217+
done()
218+
})
219+
})
191220
})
192221

193222
function createErrorTestComponents () {

0 commit comments

Comments
 (0)