关于前端:弄死-Nodejs-进程有几种方法

7次阅读

共计 4931 个字符,预计需要花费 13 分钟才能阅读完成。

有几个起因会导致 Node.js 过程终止。其中一些是能够防止的,例如抛出谬误时,而另一些是无奈避免的,例如内存不足。全局 process 是一个 Event Emitter 实例,当执行失常退出时,将收回一个 exit 事件。而后程序代码能够通过侦听这个事件来执行最初的同步清理工作。

上面是能够被动触发过程终止的一些办法:

操作 例子
手动流程退出 process.exit(1)
未捕捉的异样 throw new Error()
未兑现的 promise Promise.reject()
疏忽的谬误事件 EventEmitter#emit('error')
未解决的信号 $ kill <PROCESS_ID>

其中有许多是属于偶尔被触发的,例如未捕捉的谬误或未解决的 promise,然而其中也有为了间接使过程终止而创立的。

过程退出

应用 process.exit(code) 来终止过程是最间接的办法。这在当你晓得本人的过程曾经到了生命周期的止境时十分有用。code 值是可选的,默认值为 0,最大能够设为 255。0 示意过程运行胜利,而任何非零的数字都示意产生了问题。这些值能够被许多不同的内部工具应用。例如当测试套件运行时,非零值示意测试失败。

间接调用 process.exit() 时,不会向控制台写入任何隐式文本。如果你编写了以谬误示意模式调用此办法的代码,则你的代码应该用户输入谬误来帮忙他们解决问题。例如运行以下代码:

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

在这种状况下,单行的 Node.js 程序不会输入任何信息,只管 shell 程序的确会打印退出状态。遇到这样的过程退出,用户将无奈了解到底产生了什么事件。所以要参考上面这段程序配置谬误时会执行的代码:

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

在这种状况下,用户没会很分明产生了什么。他们运行这个程序,将谬误输入到管制台上,并且他们可能纠正这个问题。

process.exit() 办法十分弱小。只管它在程序代码中有本人的用处,但实际上相对不应该将其引入可重用的库中。如果在库中的确产生了谬误,则应抛出这个谬误,以便程序能够决定应该如何解决它。

exceprion、rejection 和收回的 Error

尽管 process.exit() 很有用,但对于运行时谬误,你须要应用其余工具。例如当程序正在解决 HTTP 申请时,一般来说谬误不应该终止过程,而是仅返回谬误响应。产生谬误的地位信息也很有用,这正是应该抛出 Error 对象的中央。

Error 类的实例蕴含对导致谬误的起因有用的元数据,例如栈跟踪信息和音讯字符串。从 Error 扩大你本人的谬误类是很常见的操作。独自实例化 Error 不会有太多副作用,如果产生谬误则必须抛出。

在应用 throw 关键字或产生某些逻辑谬误时,将引发 Error。产生这种状况时,以后栈将会“开展”,这意味着每个函数都会退出,直到一个调用函数将调用包装在 try/catch 语句中为止。遇到此语句后,将调用 catch 分支。如果谬误没有被蕴含在 try/catch 中,则该谬误被视为未捕捉。

尽管你应该应用带有 Errorthrow 关键字,例如 throw new Error('foo'),但从技术上讲,你能够抛出任何货色。一旦抛出了什么货色,它就被认为是一个例外。抛出 Error 实例十分重要,因为捕捉这些谬误的代码很可能会冀望失去谬误属性。

Node.js 外部库中罕用的另一种模式是提供一个 .code 属性,该属性是一个字符串值,在发行版之间应保持一致。比方谬误的 .code 值是 ERR_INVALID_URI,即便是供人类可读的 .message 属性可能会更改,但这个 code 值也不应被更改。

可悲的是,一种更罕用的辨别谬误的模式是查看 .message 属性,这个属性通常是动静的,因为可能回须要批改拼写错误。这种办法是很冒险的,也是容易出错的。Node.js 生态中没有完满的解决方案来辨别所有库中的谬误。

当引发未捕捉的谬误时,控制台中将打印栈跟踪信息,并且过程将回以退出状态 1 终止。这是此类异样的例子:

/tmp/foo.js:1
throw 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 是一个事件发射器,能够通过侦听 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 回绝与抛出谬误十分类似。如果 Promise 中的 reject() 办法被调用,或者在异步函数中引发了谬误,则 Promise 能够回绝。在这方面,以下两个例子大致相同:

Promise.reject(new Error('oh no'));

(async () => {throw new Error('oh no');
})();

这是输入到控制台的音讯:

(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().

与未捕捉的异样不同,从 Node.js v14 开始,这些 rejection 不会使过程解体。在将来的 Node.js 版本中,会使以后过程解体。当这些未解决的 rejection 产生时,你还能够拦挡事件,侦听 process 对象上的另一个事件:

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

事件发射器是 Node.js 中的常见模式,许多对象实例都从这个基类扩大而来,并在库和程序中应用。它们十分欢送,值得和 error 与 rejection 放在一起探讨。

当事件发射器收回没有侦听器的 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
}

确保在你应用的事件发射器实例中侦听 error 事件,以便你的程序能够失常处理事件而不会解体。

信号

信号是操作系统提供的机制,用于把用数字示意的音讯从一个程序发送到另一个程序。这些数字通常用等价的常量字符串来示意。例如,信号 SIGKILL 代表数字信号 9。信号能够有不同的用处,但通常用于终止程序。

不同的操作系统能够定义不同的信号,然而上面列表中的信号个别是通用的:

名称 编号 可解决 Node.js 默认 信号用处
SIGHUP 1 终止 父终端已敞开
SIGINT 2 终止 终端试图中断,按下 Ctrl + C
SIGQUIT 3 终止 终端试图退出,按下 Ctrl + D
SIGKILL 9 终止 过程被强行杀死
SIGUSR1 10 启动调试器 用户定义的信号 1
SIGUSR2 12 终止 用户定义的信号 2
SIGTERM 12 终止 代表优雅的终止
SIGSTOP 19 终止 过程被强行进行

如果程序能够抉择实现信号处理程序,则 Handleable 一列则为 。为 的两个信号无奈解决。Node.js 默认 这一列通知你在收到信号时,Node.js 程序的默认操作是什么。最初一个 信号用处 指出了信号对应的作用。

在 Node.js 程序中解决这些信号能够通过侦听 process 对象上的更多事件来实现:

#!/usr/bin/env node
console.log(`Process ID: ${process.pid}`);
process.on('SIGHUP', () => console.log('Received: SIGHUP'));
process.on('SIGINT', () => console.log('Received: SIGINT'));
setTimeout(() => {}, 5 * 60 * 1000); // keep process alive

在终端窗口中运行这个程序,而后按 Ctrl + C,这个过程不会被终止。它将会申明已接管到 SIGINT 信号。切换到另一个终端窗口,并依据输入的过程 ID 值执行以下命令:

$ kill -s SIGHUP <PROCESS_ID>

这演示了一个程序怎么向另一个程序发送信号,并且在第一个终端中运行的 Node.js 程序中输入它所接管到的 SIGHUP 信号。

你可能曾经猜到了,Node.js 也能把命令发送到其余程序。能够用上面的命令以把信号从长期的 Node.js 过程发送到你现有的过程:

$ node -e "process.kill(<PROCESS_ID>,'SIGHUP')"

这还会在你的第一个程序中显示 SIGHUP 音讯。当初,如果你想终止第一个过程,要运行上面的命令向其发送不能解决的 SIGKILL 信号:

$ kill -9 <PROCESS_ID>

这时程序应该完结。

这些信号在 Node.js 程序中常常用于解决失常的敞开事件。例如,当 Kubernetes Pod 终止时,它将向程序发送 SIGTERM 信号,之后启动 30 秒计时器。而后程序能够在这 30 秒内失常敞开本人,敞开连贯并保留数据。如果该过程在此计时器后仍放弃活动状态,则 Kubernetes 将向其发送一个 SIGKILL


本文首发微信公众号:前端先锋

欢送扫描二维码关注公众号,每天都给你推送陈腐的前端技术文章


欢送持续浏览本专栏其它高赞文章:

  • 深刻了解 Shadow DOM v1
  • 一步步教你用 WebVR 实现虚拟现实游戏
  • 13 个帮你进步开发效率的古代 CSS 框架
  • 疾速上手 BootstrapVue
  • JavaScript 引擎是如何工作的?从调用栈到 Promise 你须要晓得的所有
  • WebSocket 实战:在 Node 和 React 之间进行实时通信
  • 对于 Git 的 20 个面试题
  • 深刻解析 Node.js 的 console.log
  • Node.js 到底是什么?
  • 30 分钟用 Node.js 构建一个 API 服务器
  • Javascript 的对象拷贝
  • 程序员 30 岁前月薪达不到 30K,该何去何从
  • 14 个最好的 JavaScript 数据可视化库
  • 8 个给前端的顶级 VS Code 扩大插件
  • Node.js 多线程齐全指南
  • 把 HTML 转成 PDF 的 4 个计划及实现

  • 更多文章 …
正文完
 0