Vue
一、window.onerror
- 全局监听所有JS报错
- 但是它是JS级别的,识别不了Vue组件信息
- 捕捉一些Vue监听不到的错误
也可以这么写
但是,如果用try…catch…捕获的error,无法被window.onerror捕获
二、errorCaptured生命周期
- 监听所有下级组件的错误
- 返回false会阻止向上传播
window.onerror也监听到了(有向上传播)
return false 阻止向上传播: (防止重复捕获)
三、errorHandler配置
- Vue全局错误监听,所有组件错误都会汇总到这里
- 但errorCaptured返回false,不会传播到这里
没有return false ,window.onerror也没有执行,errorHandler已经是全局的监听
window.onerror与errorHandler互斥
异步错误
- 异步回调里的错误, errorHandler监听不到
- 需要使用window.onerror
只有window.onerror监听到了错误
总结
- errorCaptured监听下级组件的错误,返回false 阻止向上传播
- errorHandler监听全局Vue组件的错误
- window.onerror监听其他JS报错,如 异步
React
一、ErrorBoundary监听组件渲染报错
监听所有下级组件报错,可降级展示UI(显示 出错啦~~ 友好提示)
只监听组件渲染时的报错,不监听DOM事件、异步错误(可用try-catch、window.onerror)
只在production生产环境生效,测试环境直接抛出错误
src/ErrorBoundary.tsx
import React from 'react'
class ErrorBoundary extends React.Component {
constructor(props) {
super(props)
this.state = {
error: null // 存储当前报错信息
}
}
static getDerivedStateFromError(error) {
// 更新state 时下一次渲染能够显示降级后的UI
console.log('getDerivedStateFromError...', error)
return { error }
}
componentDidCatch(error, errorInfo) {
console.info('componentDidCatch...', error, errorInfo)
}
render() {
if (this.state.error) {
// 提示错误
return <h1>报错了</h1>
}
// 没有错误 正常渲染
return this.props.children
}
}
export default ErrorBoundary
index.tsx
ClassDemo.tsx
import React from 'react'
class ErrorDemo extends React.Component {
constructor(props:any) {
super(props)
this.state = {
num: 100
}
}
clickHandler = () => {
// this.state.num() // ErrorBoundary 无法监听DOM事件报错,需要自行 try-catch、window.onerror
}
componentDidMount() {
// throw new Error('mounted error') // ErrorBoundary 可监听渲染过程的报错
// setTimeout(() => { // 无法监听异步报错,会直接抛出
// throw new Error('setTimeout error')
// }, 1000)
}
render() {
return <div>
<p>error demo - class</p>
<button onClick={this.clickHandler}>error</button>
</div>
}
}
export default ErrorDemo
FunctionDemo.tsx
import { useState, useEffect } from 'react'
function ErrorDemo() {
const [num] = useState(100)
function clickHandler() {
// num() // ErrorBoundary 无法监听事件报错,需要自行 try-catch
}
// useEffect(() => {
// throw new Error('mounted error') // ErrorBoundary 可监听渲染过程的报错
// }, [])
return <div>
<p>error demo - functional</p>
<button onClick={clickHandler}>error</button>
</div>
}
export default ErrorDemo