node端如何处理错误?

更新日期: 2019-12-26阅读: 2k标签: 错误

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

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


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.

链接: https://fly63.com/article/detial/7712

解决Cannot read property range of null 错误

vue工程npm run serve/start/dev启动时,node_modules文件报:Cannot read property range of null 错误,该问题是babel-eslint版本更新问题导致的;

HTTP 400 错误 - 请求无效 (Bad request)

在ajax请求后台数据时有时会报 HTTP 400 错误 - 请求无效 (Bad request);出现这个请求无效报错说明请求没有进入到后台服务里;原因:前端提交数据的字段名称或者是字段类型和后台的实体类不一致

js异步错误捕获

我们都知道 try catch 无法捕获 setTimeout 异步任务中的错误,那其中的原因是什么。以及异步代码在 js 中是特别常见的,我们该怎么做才比较?

不能执行已释放Script的代码

父页面初始化声明变量a为数组(数组对象是引用类型,赋值传递的是地址),创建iframe子页面后给父页面变量a赋值,赋值后销毁iframe子页面,再次调用变量a的时候就会抛出异常‘SCRIPT5011:不能执行已释放Script的代码’。

JS错误处理:前端JS/Vue/React/Iframe/跨域/Node

js错误的实质,也是发出一个事件,处理他,error实例对象message:错误提示信息,name:错误名称(非标准属性)宿主环境赋予

nodejs提示 cross-device link not permitted, rename 错误解决方法

文件上传的功能时候,调用fs.renameSync方法错误,这个提示是跨区重命名文件出现的权限问题。先从源文件拷贝到另外分区的目标文件,然后再unlink,就可以了。

Js中使用innerHTML的缺点是什么?

如果在JavaScript中使用innerHTML,缺点是:内容随处可见;不能像“追加到innerHTML”一样使用;innerHTML不提供验证,因此我们可能会在文档中插入有效的和破坏性的HTML并将其中断

Web前端开发,必须规避的8个错误点!

现在,有越来越多所谓的“教程”来帮助我们提高网站的易用性。我们收集了一些在Web开发中容易出错和被忽略的小问题,并且提供了参考的解决方案,以便于帮助Web开发者更好的完善网站。

web前端错误监控

为什么要做前端错误监控?1. 为了保证产品的质量2. 有些问题只存在于线上特定的环境3. 后端错误有监控,前端错误没有监控,前端错误分为两类: 即时运行错误和资源加载错误

自定义错误及扩展错误

当我们在进行开发的时候,通常需要属于我们自己的错误类来反映任务中可能出现的特殊情况。对于网络操作错误,我们需要 HttpError,对于数据库操作错误,我们需要 DbError,对于搜索操作错误,我们需要 NotFoundError,等等

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!