美文网首页饥人谷技术博客
Node.js错误处理一些思路

Node.js错误处理一些思路

作者: losspm | 来源:发表于2018-01-05 17:36 被阅读133次

Node.js中的错误


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
对于我们要自定义的错误,必须要有一个思想,这些自定义的错误必须要有基本的信息,比如namemessage以及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

此时定义错误的代码就会短了很多。

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.js错误处理一些思路

    Node.js中的错误 JavaScript的任何throw机制的使用都会引起异常,异常处理必须用try/catc...

  • koa 源码解析

    koa 框架是基于 Node.js 下一代的 web server 框架, 舍弃了回调写法, 提高了错误处理效率,...

  • C语言基础教程之错误处理

    C语言被忽视的一些小东西!C语言基础教程之错误处理 C语言错误处理 C 语言不提供对错误处理的直接支持,但是作为一...

  • Docker实战--部署简单nodejs应用

    如何在Docker的container里运行Node.js程序 主体思路:一个简单的Node.js web app...

  • Node.js中的错误处理

    使用domain模块处理错误 domain模块概述 从Node.js v0.8版开始,提供domain模块。该模块...

  • GitBook 安装配置 & 导出PDF

    主要思路 安装 GitBook 终端生成HTML 使用calibre插件生成PDF 主要流程 安装node.js ...

  • 自定义错误set_error_handler(5)

    php的默认错误处理是将消息输出。但是,有时候需要定义一些其他操作,这时就需要自定义错误处理函数。php提供内置函...

  • express的错误处理

    express的错误处理 定义错误处理函数: 错误处理函数带4个参数,第一个是error 错误处理函数的定义必须在...

  • Node.js内存管理机制分享

    Node.js内存管理Node.js的一些选项GC研究例子生产环境的设置 1. Node.js如何管理内存 [解惑...

  • Swift 2 学习笔记 20.错误处理

    课程来自慕课网liuyubobobo老师 错误处理 强制退出程序 错误处理

网友评论

本文标题:Node.js错误处理一些思路

本文链接:https://www.haomeiwen.com/subject/rapsnxtx.html