持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
前言
我们回顾一下上一篇讲到的内容:window.onerror、iframe中的error、promise的error以及Script error;今天我们继续补充剩下的内容
try catch
try catch只能捕捉到同步代码,对于异步代码中的错误无能为力
try {
setTimeout(()=>{
const obj = null
console.log(obj.name)
})
} catch (error) {
console.log(error)
}
复制代码
这段代码我们是无法拿到其错误信息的,我们需要去掉try catch换成window.onerror来捕捉它
try catch语句有一个副作用:由于catch中暴露了一个error对象,导致作用域链被延长,GC可能无法及时回收整个error对象,即使catch中没有使用,所以try catch语句我们也是尽量在需要的时候再去使用,不要写无意义的try catch,或者能够使用其他方式代替的就不要用try catch
window.addEventListener('error')
当有资源加载错误时,我们可以使用相应标签的事件进行处理,例如:img的onerror事件,script的onerror事件等
img.onerror = ()=>{
alert('图片加载失败')
}
复制代码
但是实际项目中我们一般都没有写这个onerror事件,当想要去捕捉的时候又需要一个一个地添加上去,有没有一个一劳永逸的办法呢?
那就是window.addEventListener('error')
,从经验来看它应该和window.onerror一样啊,像scroll事件,我们用addEventListener一般就不需要on,而直接在window对象上设置的话又需要on
window.onscroll = handleScroll
window.addEventListener("scroll",handleScroll)
复制代码
但是在这里window.addEventListener('error')
不等于window.onerror
,我们看一下下面的示例:
function loadScript () {
const i = document.createElement('script')
i.onload = () => console.log('loaded')
// i.onerror = () => console.log('load failed')
i.src = '404.webp'
document.body.append(i)
}
function addErrorEvent () {
window.addEventListener('error', (e) => {
console.log('e', e)
}, true)
window.onerror = (...args) => {
console.log('win onerror', args)
}
}
addErrorEvent()
loadScript()
abc()
复制代码
- window.addEventListener('error')可以捕捉资源加载错误,而window.onerror只能捕捉js错误
- window.addEventListener可以绑定多个事件处理函数
- 参数不同:onerror捕捉到的有【代码行数,错误堆栈】等信息,而window.addEventListener('error')它回调函数的参数是【Event对象】,可以得到发生错误的dom,但是event对象中包含代码行数和error对象,所以后者对于前者是一个包含关系
Vue提供的error钩子
Vue中提供了一个捕捉错误的方法errorHandler/errorCaptured
全局Vue错误捕捉:errorHandler
let vuePlugin = function errorPlugin(error, _Vue) {
if (!_Vue || !_Vue.config) {
return
}
let _oldOnError = _Vue.config.errHandler
_Vue.config.errHandler = function errHandler(errMsg, vm, info) {
console.log(errMsg)
// 使用这个配置之后控制台的错误会被清空,为了保证既能够捕捉错误又不影响控制台输出,所以使用console.error来进行输出
if (typeof console !== 'undefined' && typeof console.error === 'function') {
console.error(errMsg)
}
if (typeof _oldOnError === 'function') {
_oldOnError.call(this, errMsg, vm, info)
}
}
}
复制代码
errorCaptured:钩子函数,捕捉子孙组件中的错误
类型:
(err: Error, vm: Component, info: string) => ?boolean
类似于React错误边界,返回 false 以阻止错误继续向上传播。我们可以在报错之后给页面设置错误提醒页面。
render错误钩子【只能在开发环境使用】:renderError
当render函数渲染遇到错误时提供另外一种渲染输出;相当于render渲染正常输出,而renderError渲染错误输出,但是很遗憾只能在开发环境使用,对我们来说帮助不大
React中的error钩子
React中有一个概念:错误边界,在16之后逐渐确定下来,可以使用static getDerivedStateFromError() 或 componentDidCatch()形成错误边界兜底,他们的区别在于一个是静态方法无法访问实例方法,而componentDidCatch可以访问,一般情况下我们都使用它来创建错误边界
React错误边界可以局部创建也可以全局创建
- 局部构建可以使用HOC
const ErrorBoundary = errorInfo => WrapComponent =>{
return class ErrorBoundary extends React.Component{
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
this.setState({hasError: true});
}
render() {
if (this.state.hasError) {
return <h1>页面出错啦,错误提示:{errorInfo}</h1>;
}
return <WrapComponent/>;
}
}
}
@ErrorBoundary("Businss组件出错")
class Business extends Component{
}
复制代码
- 组件最外层包裹一层ErrorBoundary
class ErrorBoundary extends Componet{
componentDidCatch(error,info){
console.log(error,info)
}
render(){
return this.props.children
}
}
<ErrorBoundary>
<Layout/>
</ErrorBoundary>
复制代码
nodejs中的报错
- 标准的 JavaScript 错误,例如EvalError、SyntaxError、RangeError、ReferenceError、TypeError和 URIError
- 由底层操作系统约束触发的系统错误,例如尝试打开不存在的文件或尝试通过关闭的套接字发送数据。
- 由应用程序代码触发的用户指定的错误。
AssertionError
是特殊的错误类,当 Node.js 检测到不应该发生的异常逻辑违规时会触发。 这些通常由node:assert
模块引发。
uncaughtException
当未捕获的 JavaScript 异常一直冒泡回到事件循环时,则会触发
'uncaughtException'
事件。发生该错误时进程将以0退出。
process.on("uncaughtException",(error,origin)=>{
// origin用来甄别是源自”promise错误“还是“同步错误”
console.log(process.stderr.fd,
`报错信息为: ${err}\n` +
`发生错误的根源: ${origin}`
)
})
复制代码
unhandledRejection
每当
Promise
被拒绝并且在事件循环的一个轮询内没有错误句柄附加到承诺时,则会触发'unhandledRejection'
事件。
process.on('unhandledRejection', (reason, promise) => {
console.log('Unhandled Rejection at:', promise, 'reason:', reason);
});
复制代码
总结
至此js错误监控就已经完结;我们重新回顾一下:try catch捕捉同步错误、window.addEventListener('error')捕捉js错误和资源错误、Vue中使用errorCaptured捕捉局部错误,errorHandler捕捉全局错误、React拥有getDerivedStateFromError和 componentDidCatch两个钩子函数;nodejs中可监听uncaughtException,unhandledRejection事件来记录错误信息