mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-02 03:57:36 +08:00
fix: avoid possible infinite loop by accessing observables in error handler (#9489)
This commit is contained in:
parent
a702d1947b
commit
ee29e41ef4
@ -4,25 +4,33 @@ import config from '../config'
|
||||
import { warn } from './debug'
|
||||
import { inBrowser, inWeex } from './env'
|
||||
import { isPromise } from 'shared/util'
|
||||
import { pushTarget, popTarget } from '../observer/dep'
|
||||
|
||||
export function handleError (err: Error, vm: any, info: string) {
|
||||
if (vm) {
|
||||
let cur = vm
|
||||
while ((cur = cur.$parent)) {
|
||||
const hooks = cur.$options.errorCaptured
|
||||
if (hooks) {
|
||||
for (let i = 0; i < hooks.length; i++) {
|
||||
try {
|
||||
const capture = hooks[i].call(cur, err, vm, info) === false
|
||||
if (capture) return
|
||||
} catch (e) {
|
||||
globalHandleError(e, cur, 'errorCaptured hook')
|
||||
// Deactivate deps tracking while processing error handler to avoid possible infinite rendering.
|
||||
// See: https://github.com/vuejs/vuex/issues/1505
|
||||
pushTarget()
|
||||
try {
|
||||
if (vm) {
|
||||
let cur = vm
|
||||
while ((cur = cur.$parent)) {
|
||||
const hooks = cur.$options.errorCaptured
|
||||
if (hooks) {
|
||||
for (let i = 0; i < hooks.length; i++) {
|
||||
try {
|
||||
const capture = hooks[i].call(cur, err, vm, info) === false
|
||||
if (capture) return
|
||||
} catch (e) {
|
||||
globalHandleError(e, cur, 'errorCaptured hook')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
globalHandleError(err, vm, info)
|
||||
} finally {
|
||||
popTarget()
|
||||
}
|
||||
globalHandleError(err, vm, info)
|
||||
}
|
||||
|
||||
export function invokeWithErrorHandling (
|
||||
|
@ -209,4 +209,42 @@ describe('Options errorCaptured', () => {
|
||||
|
||||
expect(calls).toEqual([1, 2, 3])
|
||||
})
|
||||
|
||||
// ref: https://github.com/vuejs/vuex/issues/1505
|
||||
it('should not add watchers to render deps if they are referred from errorCaptured callback', done => {
|
||||
const store = new Vue({
|
||||
data: {
|
||||
errors: []
|
||||
}
|
||||
})
|
||||
|
||||
const Child = {
|
||||
computed: {
|
||||
test() {
|
||||
throw new Error('render error')
|
||||
}
|
||||
},
|
||||
|
||||
render(h) {
|
||||
return h('div', {
|
||||
attrs: {
|
||||
'data-test': this.test
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
errorCaptured(error) {
|
||||
store.errors.push(error)
|
||||
},
|
||||
render: h => h(Child)
|
||||
}).$mount()
|
||||
|
||||
// Ensure not to trigger infinite loop
|
||||
waitForUpdate(() => {
|
||||
expect(store.errors.length).toBe(1)
|
||||
expect(store.errors[0]).toEqual(new Error('render error'))
|
||||
}).then(done)
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user