进程相关-process
// process是node的全局模块,作用比较直观,可以通过他来获取node进程相关的信息,比如运行node程序的命令行参数,或者设置进程相关信息,比如设置环境变量
环境变量 process.env
// 使用频率很高,node服务运行时候,时常会判断当前服务运行的环境
if (process.env.NODE_NEV === "production") {
console.log("生产环境");
} else {
console.log("开发环境");
}
异步 process.nextTick(fn)
// 使用的频率很高,通常勇仔异步的场景
console.log("海贼王");
process.nextTick(() => {
console.log("火影忍者");
});
console.log("死神");
// 海贼王
// 死神
// 火影忍者
// process.nextTick(fn) 和 setTimeout(fn, 0) 很像, 但是实际有实现和性能上的差异
// process.nextTick(fn) 将fn放到node事件循环的下一个 tick 里
// process.nextTick(fn) 比 setTimeout(fn,0) 的性能要高
获取命令行参数 process.argv
// process.argv 返回的是一个数组
// 元素1: node
// 元素2: 可执行文件的绝对路径
// 元素3: 其他,比如参数等
process.argv.forEach((val, index, array) => {
console.log("参数", index, ":", val);
});
// 执行 node index.js --env production
// 参数 0 : D:\nodejs\node.exe
// 参数 1 : D:\Node-learning\nodejs-learning-guide-master\practice\process\index.js
// 参数 2 : --env
// 参数 3 : production
获取 node specific 参数 process.execArgv
// 跟 process.argv 看着类似,但是差异很大,他返回的是 node specific 的参数,(也就是运行node程序持有的参数,比如 --Harmony),这部分参数不会出现在哎process.argv里面
// 执行 node --harmony index.js --nick chyingp
process.execArgv.forEach((val, index, array) => {
console.log(index, ":", val);
});
// 0 : --harmony
process.argv.forEach((val, index, array) => {
console.log(index, ":", val);
});
// 0 : D:\nodejs\node.exe
// 1 : D:\Node-learning\nodejs-learning-guide-master\practice\process\index.js
// 2 : --nick
// 3 : chyingp
当前工作路径 process.cwd() vs process.chdir(directory)
// process.cwd() 返回当前工作路径
// process.chdir(directory) 切换当前工作路径
console.log("atarting directory", process.cwd()); // atarting directory D:\Node-learning\nodejs-learning-guide-master\practice\process
try {
process.chdir("D:/Node-learning/nodejs-learning-guide-master/practice/net");
console.log("new directory", process.cwd());
} catch (error) {
console.log("chdir", error);
}
// atarting directory D:\Node-learning\nodejs-learning-guide-master\practice\process
// new directory D:\Node-learning\nodejs-learning-guide-master\practice\net
IPC 相关
// process.connected 如果当前进程是子进程,且与父进程之间通过IPC通过连接着,则为 true
// process.disconnect() 断开与父进程之间的IPC通道,此时会将 process.connected 设置为false
// 首先在 connected.js 通过 fork 创建子进程 (父子进程之间创建了IPC通道)
const child_process = require("child_process");
child_process.fork("./connectedChild.js", {
stdio: "inherit",
});
// 然后在 connectedChild.js 里面
// console.log( 'process.connected: ' + process.connected );
// process.disconnect();
// console.log( 'process.connected: ' + process.connected );
// 输出
// process.connected: true
// process.connected: false
其他
process.config 跟 node的编译配置参数有关
标准输入/标准输出/标准错误输出 process.stdin/process.stdout/process.stderr
// process.stdin、process.stdout、process.stderr 分别代表进程的标准输入、标准输出、标准错误输出。
process.stdin.setEncoding("utf-8");
process.stdout.write("请输入内容: ");
process.stdin.on("readable", () => {
const chunk = process.stdin.read();
if (chunk !== null) {
process.stdout.write(`data: ${chunk}`);
}
});
process.stdin.on("end", () => {
process.stdout.write("end");
});
// 执行 node index.js 控制台提示 请输入用户名:
// 输入内容123后 回车, 显示 data:123
用户组/用户 相关
// process.setegid(id)
// process.setegid() 获取当前用户的ID (POSIX平台才有限)
// process.getegid(id)
// process.getegid() 获取当前群组的id (POSIX平台上才有效,群组,有效群组,的区别)
// process.setegid(id)
// process.setegid() 获取当前有效群组的id (POSIX平台才有效)
// process.setgroups(groups)
// process.getgroups() 获取附加群组的id,(POSIX平台才有效)
// process.setgroups(groups)
// process.initgroups(user, extra_group)
当前进程信息
console.log(process.pid); // 返回进程的id
// 可以用来修改进程的名字,当使用ps命令,同时有多个node进程在跑的时候,作用就能体现了
console.log(process.title); // C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
运行情况/资源占用情况
process.uptime(); // 当前node进程已经运行了多长时间(单位是秒)
process.memoryUsage(); // 返回进程占用的内容,单位为字节,输入内容如下
// {
// rss: 35225600,
// heapTotal: 6057984,
// heapUsed: 3421520,
// external: 1245873,
// arrayBuffers: 10042
// }
// process.cpuUsage([previousValue]) // CPU使用时间耗时,单位为毫秒,user标识用户程序代码占用饿时间,systeem表示系统占用时间,如果当前进程占用多个内核来执行任务,name数值比实际感知的更大,
const startUsage = process.cpuUsage();
console.log(startUsage); // { user: 15000, system: 93000 }
const now = Date.now();
// 使CPU旋转500毫秒
while (Date.now() - now < 500);
console.log(process.cpuUsage(startUsage)); // { user: 516000, system: 0 }
process.hrtime(); // 一般用于做性能基准测试,返回一个数组.数组里的值为[seconds, nanoseconds](1秒等于10的九次方纳秒)
// 注意 这里的返回值,是相当于过去一个随机的时间,所以本身没有什么意义,仅当你将上一次调用返回值作为参数传入的时候才有意义
const time = process.hrtime();
setInterval(() => {
const diff = process.hrtime(time);
console.log(`benchmark took ${diff[0] * 1e9 + diff[1]} nanoseconds`);
// benchmark took 1009448100 nanoseconds
// benchmark took 2023356200 nanoseconds
// benchmark took 3025747800 nanoseconds
// benchmark took 4040026800 nanoseconds
// benchmark took 5053138200 nanoseconds
// benchmark took 6060215800 nanoseconds
}, 1000);
node 可执行程序相关信息
// process.version 返回当前node的版本 比如 v.6.1.0
// process.versions 返回node的版本 以及依赖库的版本
console.log(process.version); // v14.19.0
console.log(process.versions);
// {
// node: '14.19.0',
// v8: '8.4.371.23-node.85',
// uv: '1.42.0',
// zlib: '1.2.11',
// brotli: '1.0.9',
// ares: '1.18.1',
// modules: '83',
// nghttp2: '1.42.0',
// napi: '8',
// llhttp: '2.1.4',
// openssl: '1.1.1m',
// cldr: '40.0',
// icu: '70.1',
// tz: '2021a3',
// unicode: '14.0'
// }
// process.release 返回当前node发型版本的信息,大部分时候用不到
console.log(process.release);
// {
// name: 'node',
// lts: 'Fermium',
// sourceUrl: 'https://nodejs.org/download/release/v14.19.0/node-v14.19.0.tar.gz',
// headersUrl: 'https://nodejs.org/download/release/v14.19.0/node-v14.19.0-headers.tar.gz',
// libUrl: 'https://nodejs.org/download/release/v14.19.0/win-x64/node.lib'
// }
// process.config 返回当前node版本,编译时的参数,同样很少用到
// process.execPath node可执行程序的绝对路径,比如 'D:\nodejs\node.exe'
console.log(process.execPath);
进程运行所在环境
process.arch; // 返回当前西戎的处理器架构(字符串) 比如'arm', 'ia32', or 'x64'。
console.log(process.arch); // x64
process.platform; // 返回关于平台描述的字符串,比如 darwin、win32 等。
console.log(process.platform); // win32
警告信息 process.emitWarning(warning)
// 可以用来抛出警告信息
// process.emitWarning("Something Happened!"); // (node:29552) Warning: Something Happened!
// 可以给报警信息加个名字便于分类
process.emitWarning("Something Happened!", "CustomWarning"); // (node:46384) CustomWarning: Something Happened!
// 可以对其进行监听
process.emitWarning("Something Happened!", "CustomWarning");
process.on("warning", (warning) => {
console.log(warning.name); // CustomWarning
console.log(warning.message); // Something Happened!
console.log(warning.stack);
// CustomWarning: Something Happened!
// at demo15 (D:\Node-learning\nodejs-learning-guide-master\practice\process\index.js:253:11)
// at Object.<anonymous> (D:\Node-learning\nodejs-learning-guide-master\practice\process\index.js:260:1)
// at Module._compile (internal/modules/cjs/loader.js:1085:14)
// at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
// at Module.load (internal/modules/cjs/loader.js:950:32)
// at Function.Module._load (internal/modules/cjs/loader.js:790:12)
// at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12)
// at internal/main/run_main_module.js:17:47
});
// 也可以直接给Error对象
const myWarning = new Error("Warning! Something happened!");
myWarning.name = "CustomWarning";
process.emitWarning(myWarning); // (node:46192) CustomWarning: Warning! Something happened!
向进程发送信号 process.kill(pid, signal)
// process.kill(); //这个方法名可能让初学者感到困惑,其实并不是用来杀死进程,而是用来向进程发送信号
console.log("hello");
process.kill(process.pid, "SIGHUP");
console.log("world");
// 输出结果 hello
// 可以通过监听 SIGHUP 事件来阻止他的默认行为
process.on("SIGHUP", () => {
console.log("获取到了 关闭的信息");
});
console.log("hello");
process.kill(process.pid, "SIGHUP");
console.log("world");
// 输出 回调里面的时候并没有执行
// hello
// world
// 尝试
process.on("SIGHUP", () => {
console.log("获取到了 关闭的信息");
});
setTimeout(() => {
console.log("Exiting");
}, 0);
console.log("hello");
process.kill(process.pid, "SIGHUP");
console.log("world");
// 输出
// hello
// world
// Exiting.
// Got SIGHUP signal.
终止进程 process.exit([exitCode]) process.exitCode
// 1. process.exit([exitCode]) 可以用来立即退出程序,即使当前的操作没有执行完毕,比如 process.exit() 的代码逻辑 或者未完成的异步逻辑
// 2. 写数据到 process.stdout 之后,立即调用 process.exit() 是不保险的,因为在node里面,往 stdout 里面写数据是非阻塞的,可以跨越多个事件循环,于是,可能写到一半程序就退出了,比较保险的做法就是,通过 process.exitCode 设置退出码,然后等进程自动退出
// 3. 如果程序出现异常,必须退出的时候,那么可以抛出一个未被捕获的error,来终止进程,这个比 process.exit() 安全
//如何正确设置退出代码
//进程优雅地退出。
if (someConditionNotMet()) {
// 某些条件未满足
printUsageToStdout();
process.exitCode = 1;
}
// 整个 process.exit() 的接口说明,都告诉我们 process.exit() 这个接口并不是很可靠
事件
// beforeExit 进程退出之前触发,参数为exitCode (此时eventLoop已经空了), 如果是显示调用 process.exit()退出,或者未捕获的异常导致退出,那么 beforeExit 不会触发
TODO 待进一步验证
1. 官方文档里,对于 process.nextTick(fn) 有如下描述,如何构造用例进行测试?
>它在事件循环的后续滴答声中触发任何其他I/O事件(包括计时器)之前运行。
2. process.channel:实际测试结果,即使父、子进程间存在IPC通道,process.channel 的值依旧是undefined.(测试方法有问题?)
相关链接
// [Understanding process.nextTick()](https://howtonode.org/understanding-process-next-tick)
// [nodejs 异步之 Timer &Tick; 篇](https://cnodejs.org/topic/4f16442ccae1f4aa2700109b)