异常处理
抛出异常
程序运行时不符合预期的代码都可能抛出异常,并中断后续代码的执行。除了语法层面上的错误可能会抛出异常,我们也可以自行通过throw new Error('')
来抛出异常。
throw new Error('手动抛出的错误')
console.log('akara') // 不会输出
Error类型
Error
实例包括以下有用的属性:
message
:错误消息。name
:错误名称,为构造函数的名称。stack
:错误堆栈。
class MyError extends Error {
constructor(...props) {
super(...props)
this.name = 'MyError'
}
}
try {
throw new MyError('myMessage')
} catch (error) {
console.error(error.name + ': ' + error.message)
console.error(error.stack)
}
除了自行定义错误类型,JavaScript内部还提供了一些其他异常类型都是基于该类的,包括但不限于:
- EvalError:执行
eval()
时可能抛出。 - RangeError:数值变量或参数超出其有效范围
- ReferenceError:无效引用,尝试引用一个未被定义的变量时,将会抛出此异常
- SyntaxError:各种语法错误,如重复声明一个变量两次
Promise中的异常
在Promise内部也可以使用throw
来抛出异常,这将使得Promise实例的状态变成rejected
。
const p1 = new Promise(() => {
throw new Error('test')
})
const p2 = p1.then(() => {
throw new Error('test')
})
async function test() {
throw new Error('test')
}
const p3 = test()
异常捕获
当异常被抛出时,它会沿着函数调用链一直往上,如果我们没有捕获该异常则会在控制台看到类似这样的错误信息:
throw new Error('test') // Uncaught Error: test
const p = new Promise(() => {
throw new Error('test');
}) // Uncaught (in promise) Error: test
一般为了尽可能降低异常所带来的损失,我们应该在合适的地方使用try...catch
进行异常捕获。
try {
throw new Error('手动抛出的错误')
} catch(error) {
message.error(error.message)
}
对于rejected
状态的Promise实例来说,我们有两种方式进行异常捕获:
方法一:.catch
const p1 = new Promise(() => {
throw new Error('test');
}).catch(error => {
console.error(error.message);
});
方法二:try...catch + await
try {
await new Promise(() => {
throw new Error('test');
});
} catch (error) {
console.error(error.message)
}
未被捕获的异常
如上一节所说,如果存在一些异常没有被捕获就会在控制台中分别打印出来uncaught Error
或uncaught (in promise) Error
,为了更好的服务稳定性我们可以选择监听这类的错误信息。
对于全局的未捕获错误,即uncaught Error
,通常通过window.onerror
进行监听:
window.onerror = function(errorMessage, scriptURI, lineNo, columnNo, error) {
console.log('errorMessage: ' + errorMessage); // 异常信息
console.log('scriptURI: ' + scriptURI); // 异常文件路径
console.log('lineNo: ' + lineNo); // 异常行号
console.log('columnNo: ' + columnNo); // 异常列号
console.log('error: ' + error); // 异常堆栈信息
}
而对于Promise内部的未捕获错误,即uncaught (in promise) Error
,通常通过unhandledRejection
事件进行监听:
window.addEventListener("unhandledrejection", event => {
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
});
静态资源加载异常
上述几节主要聚焦于程序异常的抛出、捕获、监听上报,对于资源加载时的异常我们也可以监听上报,一般可以通过监听捕获阶段的error
事件来实现这一点:
window.addEventListener('error', () => {
// do something
}, true)