写点什么

在 child_process 域和错误的冒泡和捕获实践【Note.js】

作者:黎燃
  • 2022-11-26
    内蒙古
  • 本文字数:3248 字

    阅读完需:约 11 分钟

child_process

child_进程模块提供派生子进程的功能。它与 popen(3)相似但不相同。此函数主要由[child_process.spown()]函数提供:


const { spawn } = require('child_process');const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => { console.log(`输出:${data}`);});
ls.stderr.on('data', (data) => { console.log(`错误:${data}`);});
ls.on('close', (code) => { console.log(`子进程退出码:${code}`);});
复制代码


const { exec } = require('child_process');exec('my.bat', (err, stdout, stderr) => {  if (err) {    console.error(err);    return;  }  console.log(stdout);});
// 文件名带有空格的脚本:const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true });// 或:exec('"my script.cmd" a b', (err, stdout, stderr) => { // ...});
复制代码


child_进程模块还提供一些其他同步和异步可选功能。每个函数都是基于[child_process.spawn()]或[child_process.spawnSync()]实现的。[child_process.exec()]:派生一个 shell 并在该 shell 上运行命令。完成后,stdout 和 stderr 将传递给回调函数。


const { spawn } = require('child_process');const grep = spawn('grep', ['ssh']);
grep.on('close', (code, signal) => { console.log(`子进程收到信号 ${signal} 而终止`);});
// 发送 SIGHUP 到进程grep.kill('SIGHUP');
复制代码


[child_process.execFile()]:类似于[child_procedure.exec()],但命令是直接派生的,而不首先派生 shell。[child_process.f 分叉()]:派生一个新的 NodeJs 进程,并通过建立 IPC 通信通道调用指定的模块,这允许父进程和子进程相互发送信息。[child_process.execSync()]:[child_procedure.exec()]的同步函数阻止节点 J 的事件循环。[child_process.execFileSync()]:[child_cess.execFile()]的同步函数阻止节点 J 的事件循环。

options.detached

在 Windows 上,设置选项如果分离为 true,则子进程可以在父进程退出后继续运行。子进程有自己的控制台窗口。一旦启用了子进程,就不能禁用它。在非 Windows 平台上,如果选项 if detached 设置为 true,则子进程将成为新进程组和会话的领导者。请注意,子进程可以在父进程退出后继续运行,无论它们是否分离。详见 setsid(2)。


const fs = require('fs');const { spawn } = require('child_process');const out = fs.openSync('./out.log', 'a');const err = fs.openSync('./out.log', 'a');
const subprocess = spawn('prg', [], { detached: true, stdio: [ 'ignore', out, err ]});
subprocess.unref();
复制代码


默认情况下,父进程将等待分离的子进程退出。为了防止父进程等待给定的子进程,可以使用子进程 Unref()方法。这将导致父进程的事件循环排除子进程的引用计数,使父进程独立于子进程退出,除非在子进程和父进程之间建立了 IPC 通道。使用分离选项启动长时间运行的进程时,除非提供了未连接到父进程的 stdio 配置,否则父进程退出后,该进程将不会在后台继续运行。如果继承了父进程的 stdio,则子进程将保持与控制终端的连接。例如,对于长时间运行的进程,为了忽略父进程的终止,父进程的 stdio 文件描述符被分离并忽略:


const { spawn } = require('child_process');
const subprocess = spawn(process.argv[0], ['child_program.js'], { detached: true, stdio: 'ignore'});
subprocess.unref();
复制代码


如果未传递信号,[ChildProcess]对象可能会触发['error']事件。向已退出的子进程发送信号不是错误,但可能会产生不可预测的后果。特别是,如果一个进程的 PID 被重新分配给另一个进程,则该信号将被发送给该进程,这可能会导致意外的结果。注意,当函数被称为 kill 时,发送给子进程的信号实际上可能不会终止该进程。


'use strict';const { spawn } = require('child_process');
const subprocess = spawn( 'sh', [ '-c', `node -e "setInterval(() => { console.log(process.pid, 'is alive') }, 500);"` ], { stdio: ['inherit', 'inherit', 'inherit'] });
setTimeout(() => { subprocess.kill(); // 不会终止 shell 中的 node 进程}, 2000);
复制代码


一旦套接字被传递给子进程,父进程就无法再跟踪套接字何时被销毁。若要显示此属性,连接属性将变为空。发生这种情况时,不建议使用。最大连接数。建议子进程中的任何消息处理程序都应验证套接字是否存在,因为连接在发送到子进程期间可能会关闭。

cipher.update

用数据更新密码。如果给定 inputEncoding 参数,其值必须为“utf8”、“ascii”或“latin1”,并且数据参数是使用指定编码的字符串。如果未给定 inputEncoding 参数,则数据必须为 Buffer、TypedArray 或 DataView。如果数据是 Buffer、TypedArray 或 DataView,则忽略 inputEncoding。OutputEncoding 指定加密数据的输出格式,可以是“latin1”、“base64”或“hex”。如果指定了 outputEncoding,则返回具有指定编码的字符串。如果未提供 outputEncoding,将返回 Buffer。密码。update()方法可以用新数据多次调用,直到调用密码 Final()。['cipher.final()'][]调用密码。update()。final()将抛出错误。


const crypto = require('crypto');const decipher = crypto.createDecipher('aes192', 'a password');
let decrypted = '';decipher.on('readable', () => { const data = decipher.read(); if (data) decrypted += data.toString('utf8');});decipher.on('end', () => { console.log(decrypted); // Prints: some clear text data});
const encrypted = 'ca981be48e90867604588e75d04feabb63cc007a8f8ad89b10616ed84d815504';decipher.write(encrypted, 'hex');decipher.end();
复制代码


const crypto = require('crypto');const fs = require('fs');const decipher = crypto.createDecipher('aes192', 'a password');
const input = fs.createReadStream('test.enc');const output = fs.createWriteStream('test.js');
input.pipe(decipher).pipe(output);
复制代码


返回所有剩余的解密内容。如果 outputEncoding 参数是“latin1”、“ascii”或“utf8”之一,则返回字符串。如果未提供输出编码,则返回 Buffer。一旦解密了 final()方法,decipher 对象就不能再用于解密数据。正在尝试调用解密。final()多次导致抛出错误。


const crypto = require('crypto');const assert = require('assert');
// Generate Alice's keys...const alice = crypto.createDiffieHellman(2048);const aliceKey = alice.generateKeys();
// Generate Bob's keys...const bob = crypto.createDiffieHellman(alice.getPrime(), alice.getGenerator());const bobKey = bob.generateKeys();
// Exchange and generate the secret...const aliceSecret = alice.computeSecret(bobKey);const bobSecret = bob.computeSecret(aliceKey);
// OKassert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
复制代码

错误的冒泡和捕获

节点。Js 支持几种机制来冒泡和处理应用程序运行时发生的错误。如何报告和处理这些错误完全取决于错误的类型和调用的 API 的样式。所有 JavaScript 错误都将被视为异常。将立即生成异常,并使用标准 JavaScript 抛出机制抛出错误。这些都是使用 JavaScript 语言提供的 try/catch 语句处理的。


try {  const m = 1;  const n = m + z;} catch (err) {  // 在这里处理错误。}
复制代码


任何使用 JavaScript 的抛出机制都会导致异常。异常必须用 try/catch 处理,否则 Node.js 进程将立即退出。除了少数例外,同步 API(任何不接受回调函数的阻塞方法,如[fs.readFileSync])将使用 throw 来报告错误。异步 API 中的错误可以通过几种方式报告:大多数异步方法都接受回调函数,该函数接受 Error 对象作为第一个参数。如果第一个参数不是 null,而是一个 Error 实例,则表示发生了错误,应进行处理。

发布于: 刚刚阅读数: 4
用户头像

黎燃

关注

前端工程师 2022-05-06 加入

专注学习分享前端知识。

评论

发布
暂无评论
在child_process域和错误的冒泡和捕获实践【Note.js】_前端_黎燃_InfoQ写作社区