JavaScript捕获错误的方式
一、try-catch
try catch是我们常见的一种异常捕获方式
缺点1、无法捕获异步异常
比如promise和setTimeout
try {
new Promise((resolve, reject) => {
reject('err')
})
} catch (error) {
console.log('catch error:', error)
}
try {
setTimeout(() => {
console.log(a)
}, 100)
} catch (error) {
console.log('catch error:', error)
}
缺点2、无法捕获语法异常
try {
console.log('答案cp3
} catch (error) {
console.log('catch error:', error)
}
常见内置的标准错误类型
- EvalError:错误与eval()有关
- RangeError: 数值变量或者参数超出有效范围
- RefenerceError:无效引用
- SyntaxError:eval()在解析代码的过程中出现语法错误
- TypeError:变量或者参数不属于有效类型
- URLError:给encodeUrl()或者decodeUrl()传递的参数无效
二、监听error事件
有两种方式:
1.window.onerror
window.onerror = function (message, source, line, col, error) {
console.log("catch error:",{message, source, line, col, error});
// message: 错误的信息
// source: 错误发生的文件
// line: 错误发生的行数
// col: 错误发生的列数
// error: 错误对象
};
可以拿到错误的信息,堆栈,行数,列数等信息。
处于安全考虑,如果加载不同域的脚本出现错误时,语法错误的细节不会展示。
2.window.addEventListener('error', callback, useCapture)
window.addEventListener('error', (error) => {
console.log('catch error:', error)
})
两者区别
这两者很相似,语法错误、代码错误都能捕获,和try-catch一样不能捕获异步错误
window.onerror = function (message, source, line, col, error) {
console.log("catch error:",{message, source, line, col, error});
};
window.addEventListener('error', (error) => {
console.log('error:', error)
})
new Promise((resolve, reject) => {
reject('err')
})
-
window.onerror打印日志的方式比addEventListener的方式多一点。
-
如果是资源加载失败,window.onerror无法捕获。addEventListener的方式可以捕获,但是得是在捕获阶段才行。
- addEventListener的第三个参数用来指定事件的处理阶段
- 事件的处理阶段分为捕获阶段和冒泡阶段,默认为捕获阶段:false
- 捕获阶段就是addEventListener的第三个参数为true。
-
window.addEventListener('error', (error) => { console.log('catch error:', error) }, true) <img src="https://www.baidu.com/404.jpg" alt="">
三.监听unhandledrejection事件
对于上面没有捕获到的异步错误,使用监听unhandledrejection事件来捕获。
1、window.onunhandledrejection
window.onunhandledrejection = event => {
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
};
2、window.addEventListener("unhandledrejection",callback)
window.addEventListener('unhandledrejection', (error) => {
console.log('catch error:', error)
})
new Promise((resolve, reject) => {
reject('promise error')
})
注意事项
unhandledrejection只能捕获未显示处理的promise异常
// 能触发 unhandledrejection ,因为未显式处理
Promise.reject('test').then()
// 能触发 unhandledrejection ,因为未显式处理
Promise.reject('test').then(console.log)
// 不能触发 unhandledrejection ,因为已处理
Promise.reject('test').then(console.log, console.log)
// 不能触发 unhandledrejection ,因为没处理,直接抛出异常
Promise.reject('test')
五.Vue的errorHandler函数
Vue的异常捕获使用errorHandler实现,内部也是通过try-catch来捕获
Vue.config.errorHandler = (err, vm, info) => {
console.log(err, vm, info)
// err: 错误对象
// vm: 发生错误的实例
// info: 错误信息
}
throw new Error('i am err')
统一异常处理
代码中抛出的异常,一种要展示给用户,一种要反馈给开发者。
对于展示给用户的错误,一般采用alert或者toast展示;对于展示给开发者的用户一般输出到控制台,或者上报给指定服务器。
在一个函数或者一个代码块中,把抛出的异常统一捕捉起来。按照不同的类型以不同的方式展示。
对于:
需要点击确认的异常类型
// ensureError.js
function EnsureError(message = 'default message'){
this.name = 'EnsureError';
this.message = message;
this.stack = (new Error()).stack;
}
EnsureError.prototype = Object.create(Error.prototype);
EnsureError.prototype.construecor = EnsureError;
export default EnsureError;
弹窗提示的错误类型
// toastError.js
function ToastError(message = 'default message'){
this.name = 'ToastError';
this.message = message;
this.stack = (new Error()).stack;
}
ToastError.prototype = Object.create(Error.prototype);
ToastError.prototype.constructor = ToastError;
export default ToastError;
提示开发者的异常类型
// devError.js
function DevError(message = 'default message'){
this.name = 'DevError';
this.message = message;
this.stack = (new Error()).stack;
}
DevError.prototype = Object.create(Error.prototype);
DevError.prototype.constructor = DevError;
export default DevError;
异常处理器
抛出普通异常时,可以带上stackoverflow上问题的列表,方便开发者查找原因。
import EnsureError from './ensureError.js';
import ToastError from './toastError.js';
import DevError from './devError.js';
import EnsurePopup from './ensurePopup.js';
import ToastPopup from './toastPopup.js';
function errorHandler(err) {
if (err instanceof EnsureError) {
EnsurePopup(err.message);
} else if (err instanceof ToastError) {
ToastPopup(err.message);
}else if( err instanceof DevError){
DevError(err.message);
}else{
error.message += ` https://stackoverflow.com/questions?q=${encodeURI(error.message)}`
console.error(err.message);
}
}
window.onerror = (msg, url, line, col, err) => {
errorHandler(err);
}
window.onunhandledrejection = event =>{
errorHandler(event.reason);
};
export default errorHandler;