跳到主要内容

异常处理

抛出异常

程序运行时不符合预期的代码都可能抛出异常,并中断后续代码的执行。除了语法层面上的错误可能会抛出异常,我们也可以自行通过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内部还提供了一些其他异常类型都是基于该类的,包括但不限于:

  1. EvalError:执行eval() 时可能抛出。
  2. RangeError:数值变量或参数超出其有效范围
  3. ReferenceError:无效引用,尝试引用一个未被定义的变量时,将会抛出此异常
  4. 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 Erroruncaught (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)