2.11 Process对象
Process是一个全局对象,无须声明即可访问,每个Node进程都有独立的process对象。该对象中存储了当前进程的环境变量,也定义了一些事件。下面是一些例子:
2.11.1 环境变量
直接在Node repl环境中执行:
会得到一大串和当前进程相关的环境变量或者全局变量,你可以在其中查看你当前使用的Node版本号等一些信息。
输出结果:
例如开发者可以在代码中判断当前正在运行的Node属于哪个版本,并根据结果来决定是否运行含有一些最新特性的代码:
2.11.2 方法和事件
process模块定义了如下事件。
- Event: 'beforeExit':事件循环里没有要处理的事件了,退出的预备动作。
- Event: 'disconnect':子进程IPC通道关闭时触发。
- Event: 'exit':进程退出时触发。
- Event: 'message':进程间通信中使用。
- Event: 'rejectionHandled':一个Promise转换为rejected并且被捕获时触发。
- Event: 'uncaughtException':未经捕获的异常,慎用。
- Event: 'unhandledRejection':未经捕获的rejected。
- Event: 'warning':Node发出警告信息时触发。
Message、disconnect我们已经介绍过了,unhandledRejection和uncaughtException通常用做错误处理的最后一层保险,下面的代码可以保证进程不会因为出错而退出:
但不代表开发者可以省略具体错误处理的代码,我们会在第8章中详细介绍。
beforeExit比较有意思,它仅仅会在进程准备退出时触发,准备退出是指目前的事件循环没有要执行的任务了,如果我们手动捕获这一事件并在回调中增加一些额外动作,进程就不会退出。
而exit事件不同,当进程触发exit事件后,无论如何都会退出。
2.11.3 一个例子:修改所在的时区
这个需求可能并不常见,但在某些情况下可能十分有用。
假设开发者要向某台服务器提交数据,但没有和该服务器处在同一个时区内(在国内通常采用标准北京时间,所以不是很常见),这就导致开发者的时间和服务器的时间可能会相差几个小时,有的服务器会拒绝这样的请求。JavaScript获得当前的时间通常使用Date对象来实现,在stackoverflow上搜索相关的问题可以找到类似如下的代码。
代码2.37 旧版本Node中设置时区的方法
上面的一段代码将当前的时区置于零时区,试着在本地运行,输出的结果为:
上面的这段代码已经有些年头了,在早期版本的Node中这样的设置确实有效,笔者初次看到这段代码时还在使用V0.12版本。经过测试,上面的代码在v5.3.0中还可以正常发挥作用,但在比较新的版本,例如6.9.4及以上的版本中,即使TZ设置成Asia/Shanghai,返回的也始终是伦敦时间。
在旧的版本中,打印一个date对象返回的是当前时区的时间,但在新版本中直接返回的就是世界时,即greenwich时间,相比东八区要早8个小时,格式也不再是GMT格式,这代表就算要获取当前时间都要做一下额外转换。
通常可以使用Date对象提供的全局方法来进行转换。
此外date对象还有一个名为getTimezoneOffset的方法可用,用这个方法可以得到当前的时区。
在上面的代码中,虽然直接打印date对象显示的是greenwich时间,但执行getTimezoneOffset()方法返回的却是-480,表示偏移的分钟数。这代表Node其实知道我们位于哪个时区,但返回的都是Greenwich时间。
对于修改时区的问题,我们可以使用Date提供的API来进行修改,但如果不想修改之前使用TZ这一环境变量留下的代码,完全可以自己实现相关的配置。
实现timezone的修改
经过试验,虽然设置process.env.TZ的方法不能用了,但我们完全可以自己实现一套可用代码出来。
为此,我们首先在Date对象的prototype上声明一个map结构作为属性,用于存储时区名称和偏移量的关系,然后对Date类的Date方法进行修改,如果没有声明process.env.TZ变量,就默认返回原来的date对象;如果声明了该属性,就先到对应的数组中进行搜索,然后返回修改后的date对象。
代码2.38 自己实现的修改时区的方法
开发者可能会担心d.getHours()+item[1]这句代码会出现大于24的情况,所幸setHours方法已经内置了对这种情况的处理,如果小时的范围小于0或者大于24,会对日期进行相应的加减。