2021年7月13日星期二

NodeJS 进程是如何退出的

有几种因素可以导致 NodeJS 进程退出。在这些因素中,有些是可预防的,比如代码抛出了一个异常;有些是不可预防的,比如内存耗尽。process 这个全局变量是一个 Event Emitter 实例,如果进程优雅退出,process 会派发一个 exit 事件。应用代码可以监听这个事件,来做最后的清理工作。

下面的表格列举了可以导致进程退出的因素。

操作举例
手动退出process.exit(1)
未捕获的异常throw new Error()
未处理的 promise rejectionPromise.reject()
未处理的 error 事件EventEmitter#emit('error')
未处理的信号kill <PROCESS_ID>

主动退出

process.exit(code) 是最直接的结束进程的方法。code 参数是可选的,可以为 0 ~ 255 之间任何数字,默认为 0。0 表示进程执行成功,非 0 数字表示进程执行失败。

process.exit() 被使用时,控制台不会有任何输出,如果我们想在进程推出的时候像控制台输出一些错误说明信息,则需要在调用之前显示的输出错误信息。

node -e "process.exit(42)"echo $?

上面的代码直接退出了 NodeJS 进程,命令行没有任何输出信息。用户在遭遇进程退出的时候,无法获取有效的错误信息。

function checkConfig(config) { if (!config.host) { console.error("Configuration is missing 'host' parameter!"); process.exit(1); }}

在上面的代码中,我们在进程退出之前输出的明确的错误信息。

process.exit() 的功能非常强大,但是我们不应该在工具库中使用。如果在工具库中遇到的错误,我们应该以异常的形式抛出,从而让应用代码决定如何处理这个错误。

Exceptions, Rejections 和 Emitted Errors

process.exit() 在应用启动配置检查等场景中非常有用,但是在处理运行时异常时,它并不适用,我们需要其他的工具。

比如当应用在处理一个 HTTP 请求时,一个错误不应该导致进程终止,相反,我们应该返回一个含有错误信息的响应。

Error 类可以包含描述错误发生的详细信息的数据,比如调用堆栈和错误文本。通常我们会定义特定场景的 XXXError,这些 XXXError 都继承制 Error 类。

当我们使用 throw 关键字,或者代码逻辑出错时,一个错误就会被抛出。此时,系统调用栈会释放,每个函数会退出,直到遇到一个 包裹了当前调用的 try/catch 语句。如果没有 try/catch 语句,则这个错误会被认为是未捕获的异常。

通常,在 NodeJS 应用中,我们会给 Error 类定义一个 code 属性,作为用来描述具体错误的错误码,这么做的优点是可以使错误码保持唯一,同时还能使得错误码是可读的。同时,我们也可以配合 message 属性来描述具体的错误信息。

当一个未捕获的异常抛出时,控制台会打印调用堆栈,同时进程退出,退出状态码为 1.

/tmp/foo.js:1throw new TypeError('invalid foo');^Error: invalid foo at Object.<anonymous> (/tmp/foo.js:2:11) ... TRUNCATED ... at internal/main/run_main_module.js:17:47

这段控制台输出信息说明,错误发生在 foo.js 中的第 2 行第 11 列。

全局变量 process 是个 Event Emitter 实例,可以通过监听 uncaughtException 事件来处理这些未捕获异常。下面的代码展示了如何使用:

const logger = require("./lib/logger.js");process.on("uncaughtException", (error) => { logger.send("An uncaught exception has occured", error, () => { console.error(error); process.exit(1); });});

Promise Rejection 与抛出异常类似。我们可以通过调用 reject() 函数或者在 async 函数中抛出异常来是的 promise 到达 rejected 状态。下面的两段代码功能是相似的。

Promise.reject(new Error("oh no"));(async () => { throw new Error("oh no");})();

目前,在 NodeJS 14 中,Promise Rejection 不会导致进程退出,在后续的版本中,Promise Rejection 可能会导致进程退出。

下面是一段未捕获的 Promise Rejection 的控制台输出样例。

(node:52298) UnhandledPromiseRejectionWarning: Error: oh no at Object.<anonymous> (/tmp/reject.js:1:16) ... TRUNCATED ... at internal/main/run_main_module.js:17:47(node:52298) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch().

我们可以通过监听 unhandledRejection 事件来处理未捕获的 Rejection. 样例代码如下:

process.on("unhandledRejection", (reason, promise) => {});

Event Emitter 是 NodeJS 中的基础模块,应用广泛。当 Event Emitter 的 error 事件未被处理时,Event Emitter 就会抛出一个错误,同时会导致进程退出。下面是一个 Event Emitter error 的控制台输出。

events.js:306 throw err; // Unhandled 'error' event ^Error [ERR_UNHANDLED_ERROR]: Unhandled error. (undefined) at EventEmitter.emit (events.js:304:17) at Object.<anonymous> (/tmp/foo.js:1:40) ... TRUNCATED ... at internal/main/run_main_module.js:17:47 { code: 'ERR_UNHANDLED_ERROR', context: undefined}

因此,我们在使用 Event Emitter 的时候,要确保监听了 error 事件,这样在发生错误的时候,可以使得应用能够处理这些错误,避免奔溃。

信号

信号是操作信息提供了进程间通信机制。信号通常是一个数字,同时也可以使用一个字符串来标识。比如 SIGKILL 标识数字 9。不同的操作系统对信号的定义不同。下面表格里罗列的是基本通用的信号定义。

名称数字是否可处理NodeJS 默认行为信号的含义
SIGHUP1Yes退出父命令行被关闭
SIGINT2Yes退出命令行尝试中断,即 Ctrl + C
SIGQUIT3Yes退出命令行尝试退出,即 Ctrl + Z
SIGKILL9No退出强制进程退出
SIGUSR110Yes启动调试器用户自定义信号
......

原文转载:http://www.shaoqun.com/a/872517.html

跨境电商:https://www.ikjzd.com/

易麦:https://www.ikjzd.com/w/2048

aca:https://www.ikjzd.com/w/1371

吉祥邮:https://www.ikjzd.com/w/1565


有几种因素可以导致NodeJS进程退出。在这些因素中,有些是可预防的,比如代码抛出了一个异常;有些是不可预防的,比如内存耗尽。process这个全局变量是一个EventEmitter实例,如果进程优雅退出,process会派发一个exit事件。应用代码可以监听这个事件,来做最后的清理工作。下面的表格列举了可以导致进程退出的因素。操作举例手动退出process.exit(1)未捕获的异常thrown
rfq:https://www.ikjzd.com/w/251
菜鸟网:https://www.ikjzd.com/w/1547
南昌万达海洋乐园什么时候开园,南昌万达海洋乐园开园时间+地址:http://www.30bags.com/a/435515.html
南昌万达主题乐园什么时候开业,南昌万达乐园在哪:http://www.30bags.com/a/426563.html
南昌小马尔代夫 冬天来瑶湖感受异域风情的BBQ:http://www.30bags.com/a/416347.html
南昌新晋网红打卡地磨盘山乐道,投资1.6亿元,免费对外开放:http://www.30bags.com/a/225312.html
老师晚上求我桶她 老师好大好深啊把腿开开:http://lady.shaoqun.com/a/247844.html
老师让我揉她胸摸下边 撩开裙子摸摸下面流水:http://lady.shaoqun.com/m/a/248253.html
深圳扬州八怪与扬州三百年展览时间:http://www.30bags.com/a/497652.html
离婚的女人过得怎么样?论离异女性的孤独与欲望。:http://lady.shaoqun.com/a/418107.html
男的半夜去公园让女网友"下地",又抢了钱:http://lady.shaoqun.com/a/418108.html
不注意这点,订单再多也是白干!原来跨境大卖们在用它……:https://www.ikjzd.com/articles/146592

没有评论:

发表评论