
1.4.1 kp
对于Web开发者来说,需要经常启动Web服务器,但令人头疼的是,时常会遇到端口冲突的问题,一般报错如下。

在macOS系统中,我们可以通过如下方法查看TCP端口的占用情况。

如果要终止这个进程,可以采用如下方法。

或者干脆定义一个Linux alias别名也是可以的。但这样做会产生另一个问题:如果本机的某个端口被占用了,则会产生冲突。这种情况下,如果能将shell脚本封装成Node.js二进制模块,在模块内调用shell命令会变得更简单。
基于以上想法,kp模块诞生了,其含义是kill process by port,即根据端口号来终止对应的进程。那么,如何安装kp模块呢?命令如下。

在以上命令中,$代表UNIX和Linux操作系统里的普通用户,[sudo]是可选的,如果Node.js是通过nvm安装的,则不需要sudo超级管理员权限。npm install-g kp是二进制模块的安装方式,设置kp模块的参数时只需传入端口号,具体如下。

先来看一下kp模块中的package.json文件的定义,代码如下。

kp模块提供了两种用法,如下。
〇 main:模块入口,对外提供API调用的文件index.js。
〇 bin:配置kp命令对应的kp.js文件。
index.js
index.js负责提供API,是整个模块中最核心的文件,其内容具体如下。


以上代码中的debug模块可用于将代码中的调试信息打印到终端,核心部分如下。

Node.js是以单线程的模式运行的,但它使用事件驱动来处理并发,这样有助于我们在多核CPU的系统上创建多个子进程,从而提高性能。每个子进程中都含有3个流对象:child.stdin、child.stdout和child.stderr。它们可能会共享父进程的stdio流,也可以作为独立的流对象被导流。
Node.js提供了child_process模块可用于创建子进程,方法有3种,具体如下。
〇 exec-child_process.exec:使用子进程执行命令,缓存子进程的输出,并将子进程的输出以回调函数参数的形式一次性返回。
〇 spawn-child_process.spawn:使用指定的命令行参数创建新的子进程。当希望子进程向Node.js父进程返回大量数据时,比如进行图像处理、读取二进制数据等,最好使用spawn方法。
〇 fork-child_process.fork:spawn方法的特殊形式,fork用于在子进程中运行模块,例如,fork("\./son.js")相当于spawn("node",["./son.js"])。与spawn方法不同的是,fork方法会在父进程与子进程之间建立一个通信管道,用于进程间通信。
其实,ps-tree模块搭配child.kill也能终止进程,不过shell命令里有kill和killall方法,能使代码更精简。
命令行实现
为了更好地进行代码复用,源码中的kp.js会调用index.js里的API,这样可以使index.js里的API效用最大化。即kp.js是命令行实现代码,index.js提供核心API,具体代码如下。


以上代码通过调用index.js的API来实现具体的功能,唯一的差别在于,这是命令行功能,需要处理参数并组装参数,在调用index.js里的API时使用。
编写文档
没有文档的开源项目都不能算是好的项目。写文档是程序员的基本功,也是必须要掌握的。曾有人说,当两个水平相当的人同时应征同一个岗位时,HR会优先录用文档写得好的人,因为大家普遍认为擅长写文档的人思路更清晰。
在GitHub上创建项目时,默认会创建一个REAMDE.md文件,它是默认的基于Markdown语法的项目说明文件,会在GitHub项目主页上以HTML格式显示。
之所以采用Markdown编写文档,是因为它轻量、简单、易学,具体说来,Markdown的优点如下。
〇 纯文本,简单且兼容性高,可以通过任何编辑器来编写。
〇 语法简单,容易学会,容易阅读。
〇 让人专注写作内容而不是排版格式。
在写作时,不应过分关注文档格式的问题。Markdown通过将内容和样式分离,大大提高了写作效率。当内容完成后,可以通过CSS样式来灵活调整文档格式,形成一篇漂亮的文章。通过特定工具可以很方便地将Markdown文档编译成HTML或PDF等格式文件,让Markdown有更广阔的应用空间。文档示例如下。



kp模块的文档比较简单,适合学习,具备了开源项目文档的基本结构。
文档应尽量简单明了,如果太复杂,可以用Wiki或者GitPages单独建站。另外,Markdown虽然简单,但要想完全做到书写规范也不是一件容易的事,需要多多学习。
通过将Node.js和shell命令组合,能够达到1+1>2的效果。笔者非常喜欢Perl和Ruby,在npm里使用这两种脚本语言编写模块是极为有趣的,这其实也是npm的强大之处——支持多种语言。只要操作系统执行环境允许,就可以使用我们所熟悉的语言进行编程。