如何监听Vue项目报错的4种方式 

目录
  • 背景
  • onerror
  • element.onerror
  • errorHandler
  • errorCaptured
    • error传播规则(划重点)
  • 如何监听异步错误
  • 总结

背景

在开发Vue项目时,使用浏览器调试可以比较清晰的看到报的什么错、在哪报错,或者使用console.log()打印出报错信息,以便快速定位到报错源头并解决,但是如果项目上线了又怎么查看呢。对于上线项目来说,一般都是会有代码混淆以及禁用console.log(),这个时候再使用浏览器调试就有点不太方便了。另一种场景,如果要做一个前端报错监控平台,那这些报错信息又应该如何收集呢。本文就重点介绍四种方式,即error、unhandledrejection、errorHandler、errorCaptured,用于监听Vue项目可能遇到的报错。

onerror

当JavaScript运行时错误,包括语法错误,则window会触发ErrorEvent接口的error事件,并执行window.onerror()方法,用于处理监听到的错误。
如果是资源加载失败,包括img的src加载失败或者引入的script加载失败,则加载资源的元素会触发Event接口的error事件,并指定该元素上的onerror()方法处理错误。这些error不会冒泡到window,也就是说window.onerror将无法监听到报错。

特点:

  • 可以监听所有的JavaScript错误,也能监听Vue组件的报错,包括一些异步错误
  • 无法根据报错识别Vue组件的详细信息,也无法监听已经被try/catch捕获的错误
  • 无法监听资源加载失败的报错

window.onerror

window.onerror接收4个参数,分别是:

  • message: 错误信息
  • source:发生错误的资源
  • line:发生错误的行号
  • column:发生错误的列数
  • error:Error错误对象

完整用法:

window.onerror = function(message,source,line,column,error) {
    // do something
};

如果函数返回true,则会阻止执行默认事件处理函数。

window.addEventListener('error')

使用事件监听,并在全局监听error事件。使用效果同window.onerror类似,语法有所差异:

window.addEventListener('error', event => {});

注意:此event指的是ErrorEvent类型,包含了有关事件以及具体的错误信息
举个栗子:(本文涉及的示例代码都是基于Vue项目,下同)

// App.vue
// window.onerror是全局监听,因此放在入口是比较合理的,尽管也可以放在其他位置
...
<script>
export default {
    mounted() {
        window.onerror = function(message,source,line,column,error) {
            console.log('window.onerror----', message,source,line,column,error);
        }
        // 效果与上一个类似,都是挂载到全局,两者使用其一即可。如果两者都使用,会重复处理error
        window.addEventListener('error', event => {
            console.log('window error on listener---', event);
        })
    }
}
</script>
...

element.onerror

针对一些资源加载失败的情况,例如img、script,将会触发该元素的onerror()处理函数,并且error不会冒泡到window。遇到这种情况,可以手动抛出异常,就可以被全局异常监听到是资源加载失败了。

举个栗子

// child.vue
// 图片资源加载失败
<img src="123" alt="" @error="event => handleError(event)" />
...
handleError(event) {
    console.log('handleError-----', event);
    throw new Error('图片加载失败了'); // 手动抛出异常,以便全局事件可以监听到
}

errorHandler

Vue全局错误监听处理,所有组件的错误信息默认都会汇总到此。
由于errorHandler是全局配置的,因此window.onerror将会“失效”,即errorHandler能捕获的错误,onerror将不能捕获;errorHandler不能捕获的异常,onerror将捕获错误。如果errorCaptured函数返回为false,那么此error将不会传到errorHandler

举个栗子

// main.js
...
const app = createApp(App)
app.config.errorHandler = (err, vm info) => {
    console.log('errorHandle', err, vm, info);
    // err,错误对象
    // vm,发生错误的组件实例
    // info,Vue特定的错误信息,例如错误发生的生命周期、错误发生的事件
}

errorCaptured

errorCaptured是Vue生命周期中的一个,用于捕获当前组件的所有后代组件产生的错误。函数如果返回为false,则会阻止error继续上传,全局的错误监听将不能捕获该error;否则,全局的错误监听也会再处理error。

此钩子接收三个参数:

  • error:Error错误对象
  • vm:发生错误的组件实例,可访问组件属性
  • info:包含错误来源信息的字符串

在钩子函数中,可以修改组件的状态

error传播规则(划重点)

  • 默认情况下,如果定义了全局的errorHandler,所有的error都将最终汇总到errorHandler中做统一处理
  • 如果一个组件的继承链或父链存在多个errorCaptured钩子,则这些钩子将会被相同的错误逐级唤起。
  • 如果当前组件的errorCaptured钩子本身继续抛出错误,那么这些新的错误和原本的错误都将上传到父级组件的errorCaptured钩子,以及汇总到errorHandler
  • 如果一个errorCaptured钩子返回了false,则会阻止此error的继续向上传播,也就是说这个error到此就已经处理完毕了。这个会阻止其他任何被这个错误唤起的errorCaptured钩子以及全局的errorHandler。

tips:如果errorCaptured本身抛出error,return false也就不会执行了。

举个栗子也许更能说明白

代码写的比较简洁,但是“言简意赅”

// main.js
const app = createApp(App)
app.config.errorHandler = (err, vm info) => {
    console.log('errorHandle', err, vm, info); // errorHandler也会执行两次
    // err,错误对象
    // vm,发生错误的组件实例
    // info,Vue特定的错误信息,例如错误发生的生命周期、错误发生的事件
}
// App.vue
...
<!-- 引入父组件,并注册组件 -->
<FatherErrorDemo />
...
errorCaptured: (err, vm, info) => {
    console.log('根组件 捕获异常 errorCaptured', err,vm,info)
    // 根组件的errorCaptured会执行两次,先捕获FatherErrorDemo钩子自身的错误,然后捕获childErrorDemo的错误
    // 因此vm也分别指向FatherErrorDemo和childErrorDemo
    console.log('根组件 vm', vm.$data);
    // return false;
}
// FatherErrorDemo.vue
...
<div>
this is FatherErrorDemo
<!-- 引入子组件,并注册组件 -->
<childErrorDemo />
</div>
...
errorCaptured: (err, vm, info) => {
    console.log('父组件 错误捕获', err,vm,info);
    console.log('父组件 vm', vm.$data); // vm 指向childErrorDemo实例
    this.father(); // 未定义,此处会抛出错误。errorCaptured钩子函数自身产生错误
    // return false;
}
// childErrorDemo.vue
...
<div>
this is childErrorDemo
</div>
...
mounted() {
    this.child(); // 未定义,会抛出错误
}

执行结果:

根据执行过程可知:

  • 每一个error产生后,将从产生error的组件,逐级上传到父级组件的errorCaptured,直到根节点,最后汇总到errorHandler。表示error完整的生命周期
  • errorCaptured返回false,将会阻止当前error向上传递,errorHandler也就收不到此error。(本处未执行相关代码)
  • errorCaptured自身的error,将会优先向上传递,直到“被处理”或者到达errorHandler。然后才会传递捕获到的子组件错误。

如何监听异步错误

异步错误无法直接使用Vue的errorCaptured和errorHandler来监听,根据异步类型的不同,处理方式有所差异。一般来说,监听异步错误,多采用window.onerror,如果是监听Promise的错误,则使用unhandledrejection事件来监听。

举个栗子吧

// main.js
const app = createApp(App)
app.config.errorHandler = (err, vm info) => {
    console.log('errorHandle', err, vm, info); // errorHandler不会被调用
    // err,错误对象
    // vm,发生错误的组件实例
    // info,Vue特定的错误信息,例如错误发生的生命周期、错误发生的事件
}
// App.vue
...
<!-- 引入父组件,并注册组件 -->
<FatherErrorDemo />
...
mounted() {
    window.onerror = function(msg,source,line,column,err) {
      console.log('window.onerror----', msg,source,line,column,err);
      return true;
    }
    window.addEventListener('unhandledrejection', event => {
      console.log('监听Promise unhandledrejection', event)
    })
},
errorCaptured: (err, vm, info) => {
    // errorCaptured不会被调用
    console.log('根组件 捕获异常 errorCaptured', err,vm,info)
    console.log('根组件 vm', vm.$data);
    // return false;
}
// FatherErrorDemo.vue
...
<div>
this is FatherErrorDemo
</div>
...
mounted() {
    setTimeout(() => {
        this.father();
    }, 1000); // 异步执行
    new Promise((resolve, reject) => {
      this.father();
      resolve();
    })
}

执行结果

由此可见,Vue的钩子和配置函数并没有执行,但是window.onerror、unhandledrejection却可以捕获到错误。

为了不写重复代码,setTimeout和Promise我放在一起了。实际上,Promise的产生错误且没有被reject处理,那么可以通过监听unhandledrejection事件来捕获异常。setTimeout产生的错误也只能用window.onerror来捕获(使用window.addEventListener('error')也是一样)。

总结

  • 本文共总结了4种常见的监听错误的方法,监听方法没有对错,只有使用场景的不同
  • 在Vue环境中,大多数错误可使用errorHandler配置和errorCaptured钩子解决,但是不能处理异步错误
  • 异步错误根据类型的不同,可全局监听error和unhandledrejection事件
  • 全局捕获错误,可便于快速排查并定位上线项目的问题
  • 可基于错误捕获,实现前端错误监控页,也可以用于埋点、数据分析等场景。
  • 这四种方式通常组合起来使用,会实现更好的效果

到此这篇关于如何监听Vue项目报错的4种方式 的文章就介绍到这了,更多相关监听Vue项目报错内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • vue项目中Eslint校验代码报错的解决方案

    目录 vue Eslint校验代码报错 1.空格缩进,不让使用tab 2.未使用的变量报错 3.分号和引号问题 vue使用Eslint报错 解决办法很简单 vue Eslint校验代码报错 在使用脚手架创建Vue项目时,一般会安装Eslint插件,这个主要是校验代码格式和规范用的,但是它很有点让人抓狂,因为很多校验规则和代码规范,你只要不按照它的格式来,直接导致项目编译报错,运行不了项目,这个是非常令人讨厌的. 它不像idea里安装alibaba插件,校验代码规范只是会提示,并不会导致你项目都不

  • vue踩坑记-在项目中安装依赖模块npm install报错

    在维护别人的项目的时候,在项目文件夹中安装npm install模块的时候,报错如下: npm ERR! path D:\ShopApp\node_modules\fsevents\node_modules\abbrev npm ERR! code ENOENT npm ERR! errno -4058 npm ERR! syscall access npm ERR! enoent ENOENT: no such file or directory, access 'D:\ShopApp\nod

  • vue项目下,如何用命令直接修复ESLint报错

    目录 如何用命令直接修复ESLint报错 怎么修复eslint报的错误? eslint报的错误 如何修复eslint报的错误? 如何用命令直接修复ESLint报错 在写mpvue(小程序框架,其实也算是vue项目)项目过程引入ESLint代码规范,出现很多规范问题. 首先在项目的根目录下找到package.json文件,找到下面的位置,也就是“lint”这一条指令,指令后面具体内容不用深究. 然后修改成: 接下来,运行npm run lint 可以自动解决绝大多数错误,应该有可能包含一些错误只能

  • Vue项目报错:Uncaught SyntaxError: Unexpected token <

    遇到问题: 今天做一个 VUE 的项目,在引入第三方依赖的 JS 文件时,遇到了一个问题: 控制台的提示:Uncaught SyntaxError: Unexpected token < 按照提示进入文件,再看如下图: 仔细看了看 index.html 文件,发现原本我的 JS 文件是放在 /src/utils 文件夹下的,但引入 /src 和 /static 的文件是有区别的. 解决方案: 解决办法是将第三方依赖的 JS 文件放到 /static/utils 目录下,引入路径也改成:<scr

  • vue init webpack 建vue项目报错的解决方法

    使用vue init webpack 创建vue项目时报如下错误: vue init webpack my-project C:\Users\computer\AppData\Roaming\npm\node_modules\vue-cli\bin\vue-init:60 let template = program.args[0] ^^^ SyntaxError: Block-scoped declarations (let, const, function, class) not yet s

  • 解决vue项目报错webpackJsonp is not defined问题

    在vue单页面应用中,我们大概都会使用CommonsChunkPlugin这个插件. 传送门 CommonsChunkPlugin 但是在项目经过本地测试没有任何问题,打包上线后却会报错 webpackJsonp is not defined.这是因为公共文件必须在自己引用的js文件之前引用. 可以手动改文件引用,但是推荐以下解决办法: 找到build→webpack.prod.conf.js→找到HtmlWebpackPlugin插件,添加如下配置即可 chunks: ['manifest',

  • 当启动vue项目安装依赖时报错的解决方案

    目录 启动vue项目安装依赖报错 暂时想到四个原因 vue必备安装依赖 1.elementUI 2.安装sass 3.安装axios 4.安装vuex 5.安装js-cookie 启动vue项目安装依赖报错 当启动vue项目安装依赖时报错 暂时想到四个原因 1.node版本低,升级到新版本 2.执行npm cache clean,再重新npm install 3.如果是下载依赖包失败的话,可以使用cnpm淘宝镜像下载,或者yarn下载安装 4.报错一般都会有错误提示,根据错误提示进行操作 vue

  • 如何监听Vue项目报错的4种方式 

    目录 背景 onerror element.onerror errorHandler errorCaptured error传播规则(划重点) 如何监听异步错误 总结 背景 在开发Vue项目时,使用浏览器调试可以比较清晰的看到报的什么错.在哪报错,或者使用console.log()打印出报错信息,以便快速定位到报错源头并解决,但是如果项目上线了又怎么查看呢.对于上线项目来说,一般都是会有代码混淆以及禁用console.log(),这个时候再使用浏览器调试就有点不太方便了.另一种场景,如果要做一个

  • vscode中的vue项目报错Property ‘xxx‘ does not exist on type ‘CombinedVueInstance<{ readyOnly...Vetur(2339)

    问题描述: 今天早上一开机,打开项目,发现项目一片醒目的红色,查看报错原因提示: Property 'xxxx' does not exist on type 'CombinedVueInstance<{ readyOnly: unknown; businessPrice: unknown; travelStaffInfo: any; } & Record<never, any> & Vue, object, object, object, Record<never

  • Vue项目报错:parseComponent问题及解决

    目录 Vue项目报错:parseComponent 报错内容 解决步骤 Vue常见错误及解决办法 1.在配置路由并引入组件后 2.在组件中的标签和样式中图片路径出错时 3.在组件中标签没有闭合 4.在使用less定义变量是报错 本地开发环境请求服务器接口跨域的问题 Vue项目报错:parseComponent 报错内容 ERROR  Failed to compile with 1 error                                                    

  • Vue项目报错:Uncaught SyntaxError: Unexpected token '<'的解决方法

    目录 问题: 一.public下的index.html没有引入其他外部js文件. 二. public下的index.html引入其他外部js文件. 原因一.引用文件的位置不正确 原因二:配置信息不正确 原因三:script的引入类型不对 总结 问题: 最近做vue项目时,当我访问二级路由的时候,就会报Uncaught SyntaxError: Unexpected token ‘<‘错误,而我访问一级路由不会报错.翻了网上很多资料,都无法解决. 一.public下的index.html没有引入其

  • vue项目刷新当前页面的三种方式(重载当前页面数据)

    目录 vue项目刷新当前页面的三种方式(重载当前页面数据) 一.this.$router.go(0) 二.location.reload() 三.用provide / inject 组合 PS:vue项目刷新当前页面的三种方法 vue项目刷新当前页面的三种方式(重载当前页面数据) 一.this.$router.go(0) 相当于F5刷新,这种方法虽然代码很少,只有一行,但是体验很差.页面会一瞬间的白屏,体验不是很好 二.location.reload() 这种也是一样,画面一闪,体验不是很好,相

  • 解决vue打包报错Unexpected token: punc的问题

    项目中有一个功能模块是使用Vue写的,然后蛋疼的来了,写Vue的同事走了,今天需要改,懵逼状态啊,这是什么?代码还没看懂,就给我出了一个Exception.记录一下,蛋疼历程. ERROR in static/js/app.33254a875dd731a0b538.js from UglifyJs Unexpected token: punc (() [./src/mixin/mixin.js:6,8][static/js/app.33254a875dd731a0b538.js:13,19] 好

  • Vue——解决报错 Computed property "****" was assigned to but it has no setter.

    在最近的项目中遇到了如下的警告信息: [Vue warn]: Computed property " currentStep" was assigned to but it has no setter.(意思是:计算属性 currentStep被赋值了,但此它并未定义 set方法 .) 要解决这个问题,首先要明确这个问题出现的原因.这个警告是由于Vue的计算属性内部没有set方法,即:计算属性不支持值得修改(只能针对data中的值进行计算). data(){     return {

随机推荐