详解Node.JS模块 process


Posted in Javascript onAugust 31, 2020

process 模块是 nodejs 提供给开发者用来和当前进程交互的工具,它的提供了很多实用的 API。从文档出发,管中窥豹,进一步认识和学习 process 模块:

  • 如何处理命令参数?
  • 如何处理工作目录?
  • 如何处理异常?
  • 如何处理进程退出?
  • process 的标准流对象
  • 深入理解 process.nextTick

如何处理命令参数?

命令行参数指的是 2 个方面:

  • 传给 node 的参数。例如 node --harmony script.js --version 中,--harmony 就是传给 node 的参数
  • 传给进程的参数。例如 node script.js --version --help 中,--version --help 就是传给进程的参数

它们分别通过 process.argvprocess.execArgv 来获得。

如何处理工作目录?

通过process.cwd()可以获取当前的工作目录。

通过process.chdir(directory)可以切换当前的工作目录,失败后会抛出异常。实践如下:

function safeChdir(dir) {
 try {
  process.chdir(dir);
  return true;
 } catch (error) {
  return false;
 }
}

如何处理异常?

uncaughtException 事件

Nodejs 可以通过 try-catch 来捕获异常。如果异常未捕获,则会一直从底向事件循环冒泡。如是冒泡到事件循环的异常没被处理,那么就会导致当前进程异常退出。

根据文档,可以通过监听 process 的 uncaughtException 事件,来处理未捕获的异常:

process.on("uncaughtException", (err, origin) => {
 console.log(err.message);
});

const a = 1 / b;
console.log("abc"); // 不会执行

上面的代码,控制台的输出是:b is not defined。捕获了错误信息,并且进程以0退出。开发者可以在 uncaughtException 事件中,清除一些已经分配的资源(文件描述符、句柄等),不推荐在其中重启进程。

unhandledRejection 事件

如果一个 Promise 回调的异常没有被.catch()捕获,那么就会触发 process 的 unhandledRejection 事件:

process.on("unhandledRejection", (err, promise) => {
 console.log(err.message);
});

Promise.reject(new Error("错误信息")); // 未被catch捕获的异常,交由unhandledRejection事件处理

warning 事件

告警不是 Node.js 和 Javascript 错误处理流程的正式组成部分。 一旦探测到可能导致应用性能问题,缺陷或安全隐患相关的代码实践,Node.js 就可发出告警。

比如前一段代码中,如果出现未被捕获的 promise 回调的异常,那么就会触发 warning 事件。

如何处理进程退出?

process.exit() vs process.exitCode

一个 nodejs 进程,可以通过 process.exit() 来指定退出代码,直接退出。不推荐直接使用 process.exit(),这会导致事件循环中的任务直接不被处理,以及可能导致数据的截断和丢失(例如 stdout 的写入)。

setTimeout(() => {
 console.log("我不会执行");
});

process.exit(0);

正确安全的处理是,设置 process.exitCode,并允许进程自然退出。

setTimeout(() => {
 console.log("我不会执行");
});

process.exitCode = 1;

beforeExit 事件

用于处理进程退出的事件有:beforeExit 事件 和 exit 事件。

当 Node.js 清空其事件循环并且没有其他工作要安排时,会触发 beforeExit 事件。例如在退出前需要一些异步操作,那么可以写在 beforeExit 事件中:

let hasSend = false;
process.on("beforeExit", () => {
 if (hasSend) return; // 避免死循环

 setTimeout(() => {
  console.log("mock send data to serve");
  hasSend = true;
 }, 500);
});

console.log(".......");
// 输出:
// .......
// mock send data to serve

注意:在 beforeExit 事件中如果是异步任务,那么又会被添加到任务队列。此时,任务队列完成所有任务后,又回触发 beforeExit 事件。因此,不处理的话,可能出现死循环的情况。如果是显式调用 exit(),那么不会触发此事件。

exit 事件

在 exit 事件中,只能执行同步操作。在调用 ‘exit' 事件监听器之后,Node.js 进程将立即退出,从而导致在事件循环中仍排队的任何其他工作被放弃。

process 的标准流对象

process 提供了 3 个标准流。需要注意的是,它们有些在某些时候是同步阻塞的(请见文档)。

  • process.stderr:WriteStream 类型,console.error的底层实现,默认对应屏幕
  • process.stdout:WriteStream 类型,console.log的底层实现,默认对应屏幕
  • process.stdin:ReadStream 类型,默认对应键盘输入

下面是基于“生产者-消费者模型”的读取控制台输入并且及时输出的代码:

process.stdin.setEncoding("utf8");

process.stdin.on("readable", () => {
 let chunk;
 while ((chunk = process.stdin.read()) !== null) {
  process.stdout.write(`>>> ${chunk}`);
 }
});

process.stdin.on("end", () => {
 process.stdout.write("结束");
});

关于事件的含义,还是请看stream 的文档。

深入理解 process.nextTick

我第一次看到 process.nextTick 的时候是比较懵的,看文档可以知道,它的用途是:把回调函数作为微任务,放入事件循环的任务队列中。但这么做的意义是什么呢?

因为 nodejs 并不适合计算密集型的应用,一个进程就一个线程,在当下时间点上,就一个事件在执行。那么,如果我们的事件占用了很多 cpu 时间,那么之后的事件就要等待非常久。所以,nodejs 的一个编程原则是尽量缩短每一个事件的执行事件。process.nextTick 的作用就在这,将一个大的任务分解成多个小的任务。示例代码如下:

// 被拆分成2个函数执行
function BigThing() {
 doPartThing();

 process.nextTick(() => finishThing());
}

在事件循环中,何时执行 nextTick 注册的任务呢?请看下面的代码:

setTimeout(function() {
 console.log("第一个1秒");
 process.nextTick(function() {
  console.log("第一个1秒:nextTick");
 });
}, 1000);

setTimeout(function() {
 console.log("第2个1秒");
}, 1000);

console.log("我要输出1");

process.nextTick(function() {
 console.log("nextTick");
});

console.log("我要输出2");

输出的结果如下,nextTick 是早于 setTimeout:

我要输出1
我要输出2
nextTick
第一个1秒
第一个1秒:nextTick
第2个1秒

在浏览器端,nextTick 会退化成 setTimeout(callback, 0)。但在 nodejs 中请使用 nextTick 而不是 setTimeout,前者效率更高,并且严格来说,两者创建的事件在任务队列中顺序并不一样(请看前面的代码)。

以上就是详解Node.JS模块 process的详细内容,更多关于Node.JS模块 process的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
原生js和jquery中有关透明度设置的相关问题
Jan 08 Javascript
JsRender for object语法简介
Oct 31 Javascript
jQuery中:eq()选择器用法实例
Dec 29 Javascript
Javascript中3个需要注意的运算符
Apr 02 Javascript
jquery中ajax跨域方法实例分析
Dec 18 Javascript
JavaScript实现跑马灯抽奖活动实例代码解析与优化(二)
Feb 16 Javascript
关于使用js算总价的问题
Jun 23 Javascript
JS和Canvas实现图片的预览压缩和上传功能
Mar 30 Javascript
讲解vue-router之什么是编程式路由
May 28 Javascript
jquery实现聊天机器人
Feb 08 jQuery
vue+element获取el-table某行的下标,根据下标操作数组对象方式
Aug 07 Javascript
关于JavaScript数组去重的一些理解汇总
Sep 10 Javascript
谈谈JavaScript令人迷惑的==与+
Aug 31 #Javascript
vue自定义指令限制输入框输入值的步骤与完整代码
Aug 30 #Javascript
JS性能优化实现方法及优点进行
Aug 30 #Javascript
如何检测JavaScript中的死循环示例详解
Aug 30 #Javascript
JavaScript中CreateTextFile函数
Aug 30 #Javascript
详解vue组件之间的通信
Aug 30 #Javascript
如何阻止移动端浏览器点击图片浏览
Aug 29 #Javascript
You might like
php操作路径的经典方法(必看篇)
2016/10/04 PHP
Centos 6.5系统下编译安装PHP 7.0.13的方法
2016/12/19 PHP
PHP的mysqli_stat()函数讲解
2019/01/23 PHP
prototype Element学习笔记(篇二)
2008/10/26 Javascript
判断文件是否正在被使用的JS代码
2013/12/21 Javascript
jQuery - css() 方法示例详解
2014/01/16 Javascript
jquery弹窗插件colorbox绑定动态生成元素的方法
2014/06/20 Javascript
一个jquery实现的不错的多行文字图片滚动效果
2014/09/28 Javascript
Javascript中innerHTML用法实例分析
2015/01/12 Javascript
js实现模拟银行卡账号输入显示效果
2015/11/18 Javascript
javascript中不易分清的slice,splice和split三个函数
2016/03/29 Javascript
使用Promise链式调用解决多个异步回调的问题
2017/01/15 Javascript
js实现适合新闻类图片的轮播效果
2017/02/05 Javascript
jQuery插件FusionCharts实现的2D柱状图效果示例【附demo源码下载】
2017/03/06 Javascript
vue-cli监听组件加载完成的方法
2018/09/07 Javascript
JS精确判断数据类型代码实例
2019/12/18 Javascript
使用 Jest 和 Supertest 进行接口端点测试实例详解
2020/04/25 Javascript
使用eslint和githooks统一前端风格的技巧
2020/07/29 Javascript
[02:45]DOTA2英雄敌法师基础教程
2013/11/25 DOTA
Python基于twisted实现简单的web服务器
2014/09/29 Python
python中os操作文件及文件路径实例汇总
2015/01/15 Python
Python生成短uuid的方法实例详解
2018/05/29 Python
Pandas统计重复的列里面的值方法
2019/01/30 Python
python删除文件夹下相同文件和无法打开的图片
2019/07/16 Python
Python使用psutil获取进程信息的例子
2019/12/17 Python
Python 爬虫的原理
2020/07/30 Python
python爬虫scrapy图书分类实例讲解
2020/11/23 Python
html5+css3之动画在webapp中的应用
2014/11/21 HTML / CSS
HTML5 Notification(桌面提醒)功能使用实例
2014/03/17 HTML / CSS
材料物理专业个人求职信
2013/12/15 职场文书
超市优秀员工事迹材料
2014/05/01 职场文书
2014年大学班级工作总结
2014/11/14 职场文书
销售员自我评价
2015/03/11 职场文书
家庭聚会祝酒词
2015/08/11 职场文书
详细总结Python常见的安全问题
2021/05/21 Python
详解在SQLPlus中实现上下键翻查历史命令的功能
2022/03/18 SQL Server