错误处理
-
错误概述
- 错误处理是程序设计的一个重要组成部分,
javascript
中以异常的形式提供了错误处理的功能 Error
对象有三个属性name
:错误类型message
:错误描述信息stack
:错误的堆栈信息
Error
对象是所有错误对象的基础对象,其他错误对象都继承自Error
对象
- 错误处理是程序设计的一个重要组成部分,
-
错误类型
-
SyntaxError
:语法错误- 解释:语法错误是指代码不符合语法规范,导致解析错误
- 常见的原因:括号不匹配、引号不匹配、语句末尾缺少分号等
- 列子:
let age v = 18; // Uncaught SyntaxError: Unexpected identifier
-
ReferenceError
:引用错误- 解释:引用错误是指引用了不存在的变量
- 常见的原因:试图使用一个不可访问的变量、变量未声明、变量名拼写错误等
- 列子:
console.log(a); // Uncaught ReferenceError: a is not defined
-
RangeError
:范围错误- 解释:范围错误是指一个值超出了有效范围
- 常见的原因:数组长度为负数、
Number
对象的方法参数超出范围,错误的使用数字方法等 - 列子:
let arr = new Array(-1); // Uncaught RangeError: Invalid array length
-
TypeError
:类型错误- 解释:类型错误是指变量或参数不是预期类型时发生的错误
- 常见的原因:变量不是预期类型、参数不是预期类型、使用了
null
或undefined
的对象等 - 列子:
let count = 1 count(); // Uncaught TypeError: count is not a function
-
URIError
:URI错误- 解释:当使用
encodeURI()
或decodeURI()
时,如果URI格式不正确,就会抛出URIError
错误 - 常见的原因:使用
encodeURI()
或decodeURI()
时,URI格式不正确 - 列子:
decodeURI('%2'); // Uncaught URIError: URI malformed
- 解释:当使用
-
EvalError
:eval
函数执行错误- 解释:
eval
函数执行错误时,会抛出EvalError
错误 - 常见的原因:
eval
函数参数错误 - ps:现代javascript引擎已经不会抛出
EvalError
错误
- 解释:
-
InternalError
:内部错误- 解释:
javascript
引擎内部错误时,会抛出InternalError
错误 - 常见的原因:
javascript
引擎内部错误 - ps:现代javascript引擎已经不会抛出
InternalError
错误
- 解释:
-
-
抛出错误
Error
对象只有在被抛出时才会成为异常-
throw
语句- 语法:
throw expression
- 解释:
throw
语句抛出一个异常,expression
是一个表达式,可以是任何值 - 列子:
throw 'Error occurred'; // Uncaught Error occurred
- 语法:
-
异常一旦抛出,就会在程序堆栈中向上冒泡,直到被捕获为止
-
-
同步错误处理
- 常规函数的错误处理
function toUpperCase(str) { if (typeof str !== 'string') { throw new TypeError('str must be a string'); } return str.toUpperCase(); } toUpperCase(4)
同步执行的任务可以通过
try...catch
语句捕获错误try { toUpperCase(4) } catch (e) { console.log(e.message); // str must be a string }
- 生成器函数的错误处理
function* gen() { try { yield 1; } catch (e) { console.log(e.message); } } let g = gen(); g.next(); g.throw(new Error('出错了!')); // 出错了!
可以将
try...catch
语句包装在生成器中,也可以在生成器外部捕获错误function* gen() { yield 1; } let g = gen(); try { g.throw(new Error('出错了!')); } catch (e) { console.log(e.message); // 出错了! }
-
异步函数的错误处理
-
定时器错误
setTimeout(() => { throw new Error('出错了!'); }, 1000); //将在1s后抛出错误 // 以下代码是无效的,因为定时器是异步执行的,`try...catch`语句无法捕获错误 function failAfterOneSecond() { setTimeout(() => { throw new Error('出错了!'); }, 1000); } try{ failAfterOneSecond() }catch(error){ console.log(error.message) // 出错了! } function _failAfterOneSecond() { setTimeout(() => { try { throw new Error('出错了!'); } catch (e) { console.log(e.message); } }, 1000); } // 需要在定时器内部使用`try...catch`语句捕获错误 // 使用Promise处理定时器错误 function failAfterOneSecond_() { return new Promise((resolve, reject) => { setTimeout(() => { reject(new Error('出错了!')); }, 1000); }); } failAfterOneSecond_() .then((result) => { console.log(result); }) .catch((error) => { console.log(error.message); // 出错了! });
- 事件的错误处理
let emitter = new EventEmitter(); emitter.on('error', (err) => { console.log(err.message); }); emitter.emit('error', new Error('出错了!')); // 出错了! // 事件的错误处理,需要监听`error`事件 // 如果不想让程序崩溃,为了正确处理错误,必须将try...catch语句放在回调函数内部 let emitter = new EventEmitter(); emitter.on('error', (err) => { try { console.log(err.message); } catch (e) { console.log('内部错误'); } });
- onerror事件的错误处理
window.onerror = function (message, url, line, column, error) { console.log(message); // 出错了! }; throw new Error('出错了!');
- Promise对象的错误处理
function toUpperCase(str) { return new Promise((resolve, reject) => { if (typeof str !== 'string') { reject(new TypeError('str must be a string')); } resolve(str.toUpperCase()); }); } // 对函数的改造,不返回简单的字符串或者异常,而是返回一个Promise对象。分别用Promise.resolve()和Promise.reject()方法,将正确结果和错误结果,作为参数传入resolve和reject方法 toUpperCase(4) .then((result) => { console.log(result); }) .catch((error) => { console.log(error.message); }).finally(() => { console.log('finally'); }); // 任何传递给 then、catch 或 finally 的回调都是由微任务队列异步处理的,是微任务,优先于事件和计时器等宏任务执行
-
-
错误处理的最佳实践
- 不要过度处理异常
- 避免使用浏览器特定的非标准方法
- 远程记录异常信息(sentry、WeData、等其他上报库)
- 错误处理中间件
- 捕获所有未捕获的异常
- 使用
try...catch
语句捕获同步错误