Node.js API详解之 Error模块用法实例分析
作者:李小强
本文实例讲述了Node.js API详解之 Error模块用法。分享给大家供大家参考,具体如下:
Node.js API详解之 Error
Node.js 中运行的应用程序一般会遇到以下四类错误:
1.标准的 JavaScript 错误:
EvalError : 当调用 eval() 失败时抛出。
SyntaxError : 当 JavaScript 语法错误时抛出。
RangeError : 当值不在预期范围内时抛出。
ReferenceError : 当使用未定义的变量时抛出。
TypeError : 当传入错误类型的参数时抛出。
URIError : 当全局的 URI 处理函数被误用时抛出。
2.由底层操作系触发的系统错误,例如试图打开一个不存在的文件、试图通过一个已关闭的 socket 发送数据等。
3.由应用程序代码触发的用户自定义的错误。
4.断言错误是错误的一个特殊类别,每当 Node.js 检测到一个不应该发生的异常逻辑时触发。 这类错误通常由 assert 模块引起。
所有由 Node.js 引起的 JavaScript 错误与系统错误都继承自或实例化自标准的 JavaScript 类,且保证至少提供类中的属性。
错误的冒泡和捕获
说明:
Node.js 支持几种当应用程序运行时发生的错误的冒泡和处理的机制。
如何报告和处理这些错误完全取决于错误的类型和被调用的 API 的风格。
所有 JavaScript 错误都会被作为异常处理,异常会立即产生并使用标准的 JavaScript throw 机制抛出一个错误。
这些都是使用 JavaScript 语言提供的 try / catch 语句处理的。
JavaScript 的 throw 机制的任何使用都会引起异常,异常必须使用 try / catch 处理,
否则 Node.js 进程会立即退出。
除了少数例外,同步的 API(任何不接受 callback 函数的阻塞方法,例如 fs.readFileSync)会使用 throw 报告错误。
大多数的异步方法都接受一个 callback 函数,该函数会接受一个 Error 对象传入作为第一个参数。
如果第一个参数不是 null 而是一个 Error 实例,则说明发生了错误,应该进行处理。例:
const fs = require('fs'); fs.readFile('一个不存在的文件', (err, data) => { if (err) { console.error('读取文件出错!', err); return; } // 否则处理数据 });
当一个异步方法被一个 EventEmitter 对象调用时,错误会被分发到对象的 ‘error' 事件上。例:
const net = require('net'); const connection = net.connect('localhost'); // 添加一个 'error' 事件句柄到一个流: connection.on('error', (err) => { // 如果连接被服务器重置,或无法连接,或发生任何错误,则错误会被发送到这里。 console.error(err); }); connection.pipe(process.stdout);
Node.js API 中有一小部分普通的异步方法仍可能使用 throw 机制抛出异常,且必须使用 try / catch 处理。
这些方法并没有一个完整的列表;请参阅各个方法的文档以确定所需的合适的错误处理机制。
对于所有的 EventEmitter 对象,如果没有提供一个 ‘error' 事件句柄,则错误会被抛出,
并造成 Node.js 进程报告一个未处理的异常且随即崩溃,除非: 适当地使用 domain 模块或已经注册了一个 process.on(‘uncaughtException') 事件的句柄。
const EventEmitter = require('events'); const ee = new EventEmitter(); setImmediate(() => { // 这会使进程崩溃,因为还为添加 'error' 事件句柄。 ee.emit('error', new Error('这会崩溃')); });
这种方式产生的错误无法使用 try / catch 截获,因为它们是在调用的代码已经退出后抛出的。
开发者必须查阅各个方法的文档以明确在错误发生时这些方法是如何冒泡的。
Error 类
说明:
一个通用的 JavaScript Error 对象,它不表示错误发生的具体情况。
Error 对象会捕捉一个“堆栈跟踪”,详细说明被实例化的 Error 对象在代码中的位置,并可能提供错误的文字描述。
只对于加密,如果在抛出错误时可以使用 Error 对象,则会将OpenSSL错误堆栈放入到名为 opensslErrorStack 的单独属性中。
所有由 Node.js 产生的错误,包括所有系统的和 JavaScript 的错误都实例化自或继承自 Error 类。
new Error(message)
说明:
新建一个 Error 实例,并设置 error.message 属性以提供文本信息。
如果 message 传的是一个对象,则会调用 message.toString() 生成文本信息。
error.stack 属性表示被调用的 new Error() 在代码中的位置。
堆栈跟踪是基于 V8 的堆栈跟踪 API 的。
堆栈跟踪只会取(a)异步代码执行的开头或(b)Error.stackTraceLimit 属性给出的栈帧中的最小项。
demo:
throw new Error('异常信息'); // Error: 异常信息 // at Object. (/Users/xiaoqiang/Documents/work/demo/NodeApi/app.js:1:69) // at Module._compile (module.js:660:30) // at Object.Module._extensions..js (module.js:671:10) // at Module.load (module.js:573:32) // at tryModuleLoad (module.js:513:12) // at Function.Module._load (module.js:505:3) // at Function.Module.runMain (module.js:701:10) // at startup (bootstrap_node.js:193:16) // at bootstrap_node.js:617:3
Error.stackTraceLimit
说明:
Error.stackTraceLimit 属性指定了堆栈跟踪收集的栈帧数量
(无论是 new Error().stack 或 Error.captureStackTrace(obj) 产生的)。
默认值为 10 ,但可设为任何有效的 JavaScript 数值。 值改变后的变化会影响所有捕获到的堆栈跟踪。
如果设为一个非数值或负数,则堆栈跟踪不会捕捉任何栈帧。
demo:
Error.stackTraceLimit = 5; try{ const a = 1 + b; }catch(err){ console.log(err.stack); } // ReferenceError: b is not defined // at Object. (/Users/xiaoqiang/Documents/work/demo/NodeApi/app.js:3:16) // at Module._compile (module.js:660:30) // at Object.Module._extensions..js (module.js:671:10) // at Module.load (module.js:573:32) // at tryModuleLoad (module.js:513:12)
Error.captureStackTrace(targetObject[, constructorOpt])
说明:
在 targetObject 上创建一个 .stack 属性
当访问时返回一个表示代码中调用 Error.captureStackTrace() 的位置的字符串。
可选的 constructorOpt 参数接受一个函数。 如果提供了,则 constructorOpt 之上包括自身在内的全部栈帧都会被生成的堆栈跟踪省略。
demo:
const myObject = {}; Error.captureStackTrace(myObject); console.log( myObject.stack ); // Error // at Object. (/Users/xiaoqiang/Documents/work/demo/NodeApi/app.js:2:7) // at Module._compile (module.js:660:30) // at Object.Module._extensions..js (module.js:671:10) // at Module.load (module.js:573:32) // at tryModuleLoad (module.js:513:12) // at Function.Module._load (module.js:505:3) // at Function.Module.runMain (module.js:701:10) // at startup (bootstrap_node.js:193:16) // at bootstrap_node.js:617:3
error.code
说明:
error.code 属性是标识错误类别的字符标签。
详见 Node.js Error Codes
demo: try{ const a = 1 + b; }catch(err){ console.log(err.code); } // undefined
error.message
说明:
error.message 属性是错误的字符串描述,通过调用 new Error(message) 设置。
传给构造函数的 message 也会出现在 Error 的堆栈跟踪的第一行。
但是,Error 对象创建后改变这个属性可能不会改变堆栈跟踪的第一行(比如当 error.stack 在该属性被改变之前被读取)。
demo:
try{ const a = 1 + b; }catch(err){ console.log(err.message); } // b is not defined
error.stack
说明:
error.stack 属性是一个字符串,描述代码中 Error 被实例化的位置。
第一行会被格式化为 : ,
且带上一系列栈帧(每一行都以 “at ” 开头)。 每一帧描述了一个代码中导致错误生成的调用点。
V8 引擎会试图显示每个函数的名称(变量名、函数名、或对象的方法名),但偶尔也可能找不到一个合适的名称。
如果 V8 引擎没法确定一个函数的名称,则只显示帧的位置信息。 否则,在位置信息的旁边会显示明确的函数名。
注意,帧只由 JavaScript 函数产生。
demo:
try{ const a = 1 + b; }catch(err){ console.log(err.stack); } // ReferenceError: b is not defined // at Object. (/Users/xiaoqiang/Documents/work/demo/NodeApi/app.js:2:16) // at Module._compile (module.js:660:30) // at Object.Module._extensions..js (module.js:671:10) // at Module.load (module.js:573:32) // at tryModuleLoad (module.js:513:12) // at Function.Module._load (module.js:505:3) // at Function.Module.runMain (module.js:701:10) // at startup (bootstrap_node.js:193:16) // at bootstrap_node.js:617:3
AssertionError 类
说明:
Error 的子类,表示断言失败。 这种错误通常表示实际值和预期值不相等。
demo:
const assert = require('assert'); assert.strictEqual(1, 2); // AssertionError [ERR_ASSERTION]: 1 === 2
RangeError 类
说明:
Error 的一个子类,表明一个函数的一个给定的参数的值不在可接受的集合或范围内;
无论是一个数字范围还是给定函数参数的选项的集合。
demo:
require('net').connect(-1); // RangeError [ERR_SOCKET_BAD_PORT]: Port should be > 0 and < 65536. Received -1.
ReferenceError 类
说明:
Error 的一个子类,表明试图访问一个未定义的变量。 这些错误通常表明代码有拼写错误或程序已损坏。
虽然客户端代码可能产生和传播这些错误,但在实践中,只有 V8 引擎会这么做。
demo:
console.log( a ); // ReferenceError: a is not defined
SyntaxError 类
说明:
Error 的一个子类,表明程序不是有效的 JavaScript 代码。 这些错误是代码执行的结果产生和传播的。
代码执行可能产生自 eval、Function、require 或 vm。 这些错误几乎都表明程序已损坏。
demo:
eval('**'); // SyntaxError: Unexpected token **
TypeError 类
说明:
Error 的一个子类,表明提供的参数不是一个被允许的类型。
例如,将一个函数传给一个期望字符串的参数会被视为一个 TypeError。
demo:
require('url').parse(() => { }); // TypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received type function
System Error 类
说明:
系统错误是当程序运行环境中发生异常时产生的。
有单独的异常类,并且有单独的属性:
error.code属性是一个表示错误码的字符串,总是 E 带上一串大写字母。
error.errno属性是一个数值或字符串。 如果返回一个数值,则数值是一个负数,
对应 libuv 错误处理 中定义的错误码。 如果返回一个字符串,则同 error.code。
error.syscall属性是一个字符串,描述失败的 系统调用。
error.path属性是一个字符串,包含了相关不可用路径名。
error.address属性是对链接失败的地址的描述。
error.port是一个链接端口不可用的端口值
异常与错误
说明:
JavaScript 异常是一个作为一个无效操作的结果或作为一个 throw 声明的目标所抛出的值。
虽然它不要求这些值是 Error 的实例或继承自 Error 的类的实例,
但所有通过 Node.js 或 JavaScript 运行时抛出的异常都是 Error 实例。
有些异常在 JavaScript 层是无法恢复的。 这些异常总会引起 Node.js 进程的崩溃。
例如 assert() 检测或在 C++ 层调用的 abort()。
系统错误
说明:
系统错误是当程序运行环境中发生异常时产生的。
特别是,当应用程序违反了操作系统的限制时发生的操作错误,例如试图读取一个不存在的文件或用户没有足够的权限。
系统错误通常产生于系统调用层级。
在大多数 Unix 系统上,可通过运行 man 2 intro、man 3 errno、或在线文档获取错误代码的详细清单和含义。
系统错误是由扩展的 Error 对象加上附加属性表现的。
常见的系统错误:
以下列表是不完整的,但列举了编写 Node.js 程序时会遇到的一些常见的系统错误。 详细的列表可从 ERRNO 文档找到。
EACCES (拒绝访问): 试图以被一个文件的访问权限禁止的方式访问一个文件。EADDRINUSE (地址已被使用): 试图绑定一个服务器(net、http 或 https)到本地地址,但因另一个本地系统的服务器已占用了该地址而导致失败。
ECONNREFUSED (连接被拒绝): 无法连接,因为目标机器积极拒绝。 这通常是因为试图连接到外部主机上的废弃的服务。
ECONNRESET (连接被重置): 一个连接被强行关闭。 这通常是因为连接到远程 socket 超时或重启。 常发生于 http 和 net 模块。
EEXIST (文件已存在): 一个操作的目标文件已存在,而要求目标不存在。
EISDIR (是一个目录): 一个操作要求一个文件,但给定的路径是一个目录。
EMFILE (系统打开了太多文件): 已达到系统文件描述符允许的最大数量,且描述符的请求不能被满足直到至少关闭其中一个。 当一次并行打开多个文件时会发生这个错误,尤其是在进程的文件描述限制数量较低的操作系统(如 macOS)。 要解决这个限制,可在运行 Node.js 进程的同一 shell 中运行 ulimit -n 2048。
ENOENT (无此文件或目录): 通常是由 fs 操作引起的,表明指定的路径不存在,即给定的路径找不到文件或目录。
ENOTDIR (不是一个目录): 给定的路径虽然存在,但不是一个目录。 通常是由 fs.readdir 引起的。
ENOTEMPTY (目录非空): 一个操作的目标是一个非空的目录,而要求的是一个空目录。 通常是由 fs.unlink 引起的。
EPERM (操作不被允许): 试图执行一个需要更高权限的操作。
EPIPE (管道损坏): 写入一个管道、socket 或 FIFO 时没有进程读取数据。 常见于 net 和 http 层,表明远端要写入的流已被关闭。
ETIMEDOUT (操作超时): 一个连接或发送的请求失败,因为连接方在一段时间后没有做出合适的响应。 常见于 http 或 net。 往往标志着 socket.end() 没有被正确地调用
希望本文所述对大家node.js程序设计有所帮助。