#Node.js プロセスが終了する理由はいくつかあります。これらの中には、エラーがスローされた場合など、回避可能なものもありますが、メモリ不足など、回避できないものもあります。グローバル process
は、実行が正常に終了したときに exit
イベントを発行するイベント エミッター インスタンスです。プログラム コードは、このイベントをリッスンすることで、最終的な同期クリーンアップ作業を実行できます。
# #操作 | 例 |
手動プロセス終了 |
process.exit(1)
|
キャッチされない例外 |
throw new Error()
|
未達成の約束 | Promise.reject()
|
無視されたエラー イベント |
EventEmitter#emit('error')
|
未処理のシグナル |
$ kill
|
それらの多くは、キャッチされなかったエラーや未処理の Promise など、誤ってトリガーされますが、プロセスを直接終了するために作成されるものもあります。
プロセスの終了
process.exit(code)
を使用するのが、プロセスを終了する最も直接的な方法です。これは、プロセスがライフサイクルの終わりに達したことがわかっている場合に役立ちます。 code
値はオプションで、デフォルト値は 0 で、最大値は 255 に設定できます。0 はプロセスが正常に実行されたことを示し、ゼロ以外の数値は問題が発生したことを示します。これらの値は、さまざまな外部ツールで使用できます。たとえば、テスト スイートを実行すると、ゼロ以外の値はテストが失敗したことを示します。
process.exit()
を直接呼び出す場合、暗黙的なテキストはコンソールに書き込まれません。エラー表現を使用してこのメソッドを呼び出すコードを作成する場合、コードはユーザーにエラーを出力して、問題の解決に役立てる必要があります。たとえば、次のコードを実行します。
$ node -e "process.exit(42)"
$ echo $?
ログイン後にコピー
この場合、シェル プログラムは終了ステータスを出力しますが、単一行の Node.js プログラムは情報を出力しません。このようなプロセスの終了に遭遇すると、ユーザーは何が起こったのか理解できなくなります。したがって、プログラムが正しく構成されていない場合に実行される次のコードを参照してください。
function checkConfig(config) {
if (!config.host) {
console.error("Configuration is missing 'host' parameter!");
process.exit(1);
}
}
ログイン後にコピー
この場合、ユーザーは何が起こったのか明確に理解できません。彼らはプログラムを実行し、エラーをコンソールに出力し、問題を修正することができます。
process.exit()
このメソッドは非常に強力です。プログラム コード内で独自の用途がありますが、再利用可能なライブラリには決して導入しないでください。ライブラリでエラーが発生した場合は、プログラムがその処理方法を決定できるように、このエラーをスローする必要があります。
例外、拒否、およびエラーの発行
process.exit()
は便利ですが、実行時エラーの場合は別のツールを使用する必要があります。たとえば、プログラムが HTTP リクエストを処理している場合、通常、エラーによってプロセスが終了するのではなく、エラー応答のみを返す必要があります。エラーが発生した場所、つまり Error
オブジェクトがスローされる場所を知ることも役立ちます。
Error
クラスのインスタンスには、スタック トレース情報やメッセージ文字列など、エラーの原因に関する有用なメタデータが含まれています。独自のエラー クラスを Error
から拡張するのが一般的です。 Error
をインスタンス化するだけでは多くの副作用は発生しないため、エラーが発生した場合はスローする必要があります。
Error
は、throw
キーワードが使用された場合、または特定のロジック エラーが発生した場合にスローされます。これが発生すると、現在のスタックが「アンロール」されます。つまり、呼び出し関数が呼び出しを try/catch
ステートメントでラップするまで、すべての関数が終了します。このステートメントが見つかった後、catch
ブランチが呼び出されます。エラーが try/catch
に含まれていない場合、エラーは捕捉されなかったとみなされます。
技術的には、throw new Error('foo')
Talk など、Error
とともに throw
キーワードを使用する必要がありますが、スローすることもできます。何でも。何かがスローされると、それは例外とみなされます。これらのエラーをキャッチするコードはおそらく error 属性を期待するため、Error
インスタンスをスローすることが重要です。
Node.js 内部ライブラリで一般的に使用されるもう 1 つのパターンは、リリース間で変更される文字列値である .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 は拒否される可能性があります。この点に関して、次の 2 つの例はほぼ同じです:
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 以降では、キャッチされない例外とは異なり、これらの拒否はプロセスをクラッシュさせないでください。 Node.js の将来のバージョンでは、これにより現在のプロセスがクラッシュします。また、これらの未処理の拒否が発生したときにイベントをインターセプトし、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
。
更多编程相关知识,请访问:编程视频!!
以上がNode.js プロセスをアクティブに終了するためのいくつかの方法の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。