node端如何处理错误?
作者:互联网
JavaScript的任何throw机制的使用都会引起异常,异常处理必须用try/catch来进行处理,否则nodejs进程会立即退出。
同步的API会使用throw来报告错误。
但是异步的API可能使用多种方法来报告错误---大多数异步API发生错误,采用callback方式来处理异常,其中callback的第一个参数就是err,如果第一个参数为null,而非err的话,则正确执行后面指令,反之为error的话,就会处理相应错误。
如下所示:
const fs = require('fs'); fs.readfile('a file doesn`t exist', (err, data)=>{ if(err){ console.log('readfile failed', err); } })
---当一个异步的方法被```EventEmitter```调用时候,错误会被分发到对象的```error```事件上```
const net = require('net');
const connection = net.connect('localhost');
// 添加一个 'error' 事件句柄到一个流:
connection.on('error', (err) => {
// 如果连接被服务器重置,或无法连接,或发生任何错误,则错误会被发送到这里。
console.error(err);
});
connection.pipe(process.stdout);
``````error```的事件机制常见于基于流和基于事件触发器的API,它们本身就代表了一系列异步操作。
对于所有的```EventEmitter```对象,如果没有提供一个```error```句柄,随后会抛出一个错误,nodejs进程会立即崩溃,
除非:适当地使用```domain```模块或已经注册了一个 ```process.on('uncaughtException')```事件的句柄。```
const EventEmitter = require('events');
const ee = new EventEmitter();
setImmediate(() => {
// 这会使进程崩溃,因为还为添加 'error' 事件句柄。
ee.emit('error', new Error('这会崩溃'));
});
```
一个通用的JavaScript的error对象,不会说明错误发生的具体情况,Error对象会捕捉一个"堆栈跟踪",详细的说明错误在代码中的具体位置,并且为错误提供文字描述。
自定义错误(Customer Errors)
对于Nodejs抛出的error,由于在实际工程中,如果一个一个的去定义错误,效率太低,因此可以利用类别的思想。在此基础上可以将错误具体分为HttpError,对于数据库操作的错误可以分为DbError,对于Searching Operations的操作错误分成NotFoundError。
对于我们要自定义的错误,必须要有一个思想,这些自定义的错误必须要有基本的信息,比如name,message以及stack等,但是这些自定义的错误也要有属于自身的特性。
对于这些自定义的错误,我们最好通过inherit from Error,这样以来,我们就可以通过obj instanceof Error来确认错误对象。
当我们一步一步创建我们的应用的时候,我们自定义的错误自然而然的就会慢慢形成一个等级阶层,比如HttpTimeoutError也许就是继承自HttpError。
Extending Error
假设我们目前有一个函数,readUser(JSON),这个函数可以通过JSON形式读取用户信息。
从一个JSON对象开始,如下
let json = `{"name": "John", "age": 20}`
一般而言,我们使用JSON.parse来解析,但是如果收到了错误的JSON格式,则会报出SyntaxError的错误,但是即使是JSON合法的,也不代表是有效的用户,有可能遗失必要的信息,假设所有要求的信息都有,但是不一定有效,我们之前的函数readUser(JSON)不仅仅会读取,而且会验证数据的正确性,如果是不合法的JSON格式,则会抛出SyntaxError,对于另一种错误,比如验证信息和数据库的信息不匹配,此时就应该抛出ValidationError,此时的ValidationError``应该是继承自Error,具体关于ValidationError```的代码如下
// The "pseudocode" for the built-in Error class defined by JavaScript itself
class Error {
constructor(message) {
this.message = message;
this.name = "Error"; // (different names for different built-in error classes)
this.stack = <nested calls>; // non-standard, but most environments support it
}
}
Validation的大类继承于Error
class ValidationError extends Error {
constructor(message) {
super(message); // (1)
this.name = "ValidationError"; // (2)
}
}
function test() {
throw new ValidationError("Whoops!");
}
try {
test();
}
catch(err) {
alert(err.message); // Whoops!
alert(err.name); // ValidationError
alert(err.stack); // a list of nested calls with line numbers for each
}
我们将Validation用在readUser里面
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}// Usage
function readUser(json) {
let user = JSON.parse(json);
if (!user.age) {
throw new ValidationError("No field: age");
}
if (!user.name) {
throw new ValidationError("No field: name");
}
return user;
}
// Working example with try..catch
try {
let user = readUser('{ "age": 25 }');
}
catch (err) {
if (err instanceof ValidationError) {
alert("Invalid data: " + err.message); // Invalid data: No field: name
} else if (err instanceof SyntaxError) { // (*)SyntaxError是内置在JSON.parse()中的
alert("JSON Syntax Error: " + err.message);
} else {
throw err; // unknown error, rethrow it (**) catch仅仅知道如何去处理已经定义的错误,
//遇到未定义的错误的时候,让其直接fall through
}
}
对于Validation来说,属于非常基本的类别,也许会出现本来应该在年龄那里填写数字,但是传进去的值却不是数字,此时就会有粒度更细的class来分别这类错误,比如说PropertyRequiredError
class PropertyRequiredError extends ValidationError {
constructor(property) {
super("No property: " + property);
this.name = "PropertyRequiredError";
this.property = property;
}
}
但是每次定义this.property = property很麻烦,每创建一个类别的时候就需要定义一次,我们可以将this.constructor.name赋值于this.name,定义为MyError
class MyError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
}
}
class ValidationError extends MyError { }
class PropertyRequiredError extends ValidationError {
constructor(property) {
super("No property: " + property);
this.property = property;
}
}
// name is correct
alert( new PropertyRequiredError("field").name ); // PropertyRequiredError
此时定义错误的代码就会短了很多。
广州品牌设计公司https://www.houdianzi.com
Wrapping Exception
随之具体情况的细分下去,readUser可能要处理的错误会越来越多,但是针对每一个错误,都得加一个if...try/catch明显效率太低。
目前这种情况下,创建一个ReadError的类别,用来代表一类错误的类别,如果一个错误发生在ReadError里,此时,我们会将错误捕获,并且抛出ReadError,此时我们仍会在cause里面对原始错误信息保持追踪,外层代码就仅仅需要去检查ReadError就可以了。以下是示例
class ReadError extends Error {
constructor(message, cause) {
super(message);
this.cause = cause;
this.name = 'ReadError';
}
}
class ValidationError extends Error { /*...*/ }
class PropertyRequiredError extends ValidationError { /* ... */ }
function validateUser(user) {
if (!user.age) {
throw new PropertyRequiredError("age");
}
if (!user.name) {
throw new PropertyRequiredError("name");
}
}
function readUser(json) {
let user; try {
user = JSON.parse(json);
}
catch (err) {
if (err instanceof SyntaxError) {
throw new ReadError("Syntax Error", err);
} else {
throw err;
}
}
try {
validateUser(user);
}
catch (err) {
if (err instanceof ValidationError) {
throw new ReadError("Validation Error", err);
} else {
throw err;
}
}
}try {
readUser('{bad json}');
} catch (e) {
if (e instanceof ReadError) {
alert(e); // Original error: SyntaxError: Unexpected token b in JSON at position 1
alert("Original error: " + e.cause);
} else { throw e;
}
}
按照以上代码,外层结构的代码就只需要去检查instanceof ReadError,而不需要去将所有的情况罗列出来了。
这种方式名称叫做Wrapping Exception.
标签:node,err,错误,ValidationError,如何,Error,message,处理错误,name 来源: https://www.cnblogs.com/xiaonian8/p/14017525.html