现在构建前端应用程序不像以前那么简单,现在,应用程序更加复杂和多样。这就需要在构建前端应用程序的时候考虑很多,错误/异常处理是最重要的方面之一。在应用程序中拥有良好的错误处理机制可以带来很多的好处,如下:
- 良好的错误处理机制可以避免应用程序在出现未处理的异常时崩溃
- 在生产环境下,可以轻松地存储或者跟踪错误记录日志,以便异常的处理
- 可以统一处理错误信息,例如在不破坏应用程序交互的情况下,更改错误信息展示UI
- 有助于改善用户体验
在前端应用程序中,最常见的错误/异常类型可能包括以下几种:
- 语法错误:使用了一些错误的语法
- 运行时错误:由于执行期间的非法操作导致的
- 逻辑错误:由于程序逻辑错误
- Http 错误:API 返回的错误
有很多方法可以解决上面的问题,例如使用
eslint
来检查语法错误,使用适当的try-catch
语句处理运行时错误,通过适当的单页或者集成测试减少逻辑错误,http
错误可以通过使用Promise
来处理。之前在文章《浅谈前端异常监控平台实现方案》中简单介绍前端异常监控的实现方案,在本文中,将推荐一种在 Vue 应用程序中实现错误/异常处理机制。
全局配置
Vue 应用程序有一个全局配置
Vue.config
,可以配置禁止日志和告警、devtools、错误处理程序等等。可以用自己的配置覆盖这些配置,对于错误处理,可以为其分配一个处理函数
Vue.config.errorHandler
。在整个应用程序中,任何 Vue实例(Vue组件)中的任何未捕获异常都会调用该处理程序。以下代码片段为Vue 应用程序注册一个错误处理方法(一般在项目的main.js
文件中):/** * * @param {*} error 错误跟踪 * @param {*} vm 组件错误 * @param {*} info 特定的错误信息,如生命周期钩子、事件等。 */ Vue.config.errorHandler = (error, vm, info) => { console.info(error); console.info(vm); console.info(info); };
处理程序包含 3 个参数:
error
:完整的错误跟踪,包含message
和error stack
vm
:发生错误的Vue组件/实例info
: 特定的错误信息,例如生命周期钩子、事件等。
Vue.config.errorHandler
捕获特定于Vue实例的错误,但无法捕获 Vue 实例之外的错误,如服务。要捕获 Vue 实例之外的错误,可以使用
window.onerror
事件,可以注册一个错误处理函数,该函数将捕获所有非特定于 Vue 实例的未处理异常。下面的代码片段为其应用注册window.onerror
异常处理函数:window.onerror = function(message, source, lineno, colno, error) { // TODO: 定义跟踪逻辑 };
自定义异常组件
通常项目中有一些可预知的异常需要自定义 UI ,可以自定义异常组件来统一接管异常的处理。实现的逻辑是如果有异常显示异常信息,否则就显示组件信息,代码如下:
<template> <div> <slot v-if="errors" name="errors"> <a-alert :message="errors.title" :description="errors.description" show-icon type="warning" class="mb-2" > </a-alert> </slot> <slot v-else></slot> </div> </template> <script> export default { name: "QtErrorContainer", props: { errors: Object, // {title:"500错误",description:"数据库连接超时"} }, }; </script>
以上面的组件作为容器来加载其他组件,如通过后台接口拉取列表数据,调用如下:
<QtErrorContainer :errors="errors"> <a-table ></a-table> </QtErrorContainer>
上面的代码在
errors
为null
或者false
的时候,显示表格组件<a-table></a-table>
,否则不显示而显示异常信息。这样实现好处就是所有可预知的异常都由统一的组件来处理,提高复用和灵活性。日志处理
对于日志处理,可以封装为一个独立的类,如
logger
,负责收集Vue中所有的异常日志,输出到控制台或者通过接口发送到服务器存储或借助第三方日志跟踪平台,只需要修改logger
的处理方式即可,如下:import { environment } from "@/environment/"; /** * Logger 日志类 */ class Logger { /** * @constructor AppLogger */ constructor() { this.init(); } init() { if (environment !== "production") { this.log = console.log.bind(console); this.debug = console.debug.bind(console); this.info = console.info.bind(console); this.warn = console.warn.bind(console); this.error = console.error.bind(console); this.toServer = this.error; } else { /** 在生产的情况下,替换函数定义 */ this.log = this.debug = this.info = this.warn = this.error = () => {}; /** TODO: 方法中可以增加接口或者第三方平台跟踪的逻辑 */ this.toServer = (err) => { console.error(err); }; } } } const logger = new Logger(); export { logger };
可以将
logger
类引用到上面的全局配置的处理方法中,如下:import Vue from "vue"; import { logger } from "@/logger"; /** * * @param {*} error 错误跟踪 * @param {*} vm 组件错误 * @param {*} info 特定的错误信息,如生命周期钩子、事件等。 */ Vue.config.errorHandler = (error, vm, info) => { logger.toServer({ error, vm, info }); }; window.onerror = function (message, source, lineno, colno, error) { logger.toServer({ message, source, lineno, colno, error }); };
总结
错误处理对于应用程序非常重要,在本文中,讨论了
Vue.config.errorHandler
使用生命周期钩子的全局错误处理程序和自定义组件来处理可预知的异常。本文提供了基本细节,借助这些细节,可以轻松实现应用程序的错误处理并记录它们,这将有助于创建更好的用户体验。