《Node应用程序构建——使用MongoDB和Backbone》一第 1 章 Node.js基本介绍1.1 Node和npm命令

  1. 云栖社区>
  2. 博客>
  3. 正文

《Node应用程序构建——使用MongoDB和Backbone》一第 1 章 Node.js基本介绍1.1 Node和npm命令

异步社区 2017-05-02 14:10:00 浏览1630
展开阅读全文

本节书摘来自异步社区《Node应用程序构建——使用MongoDB和Backbone》一书中的第1章,第1.1节,作者【美】Mike Wilson,更多章节内容可以访问云栖社区“异步社区”公众号查看

第 1 章 Node.js基本介绍

写给PHP开发者的Node.js学习指南
我们假定你有一个PHP代码库需要移植到Node.js。在可预见的未来你需要为用户提供PHP和Node.js两个代码库,这意味着你需要同步更新和改进这两个代码库。但是你并不了解Node.js,也没有做过任何有关Node.js的开发。那么该从哪里下手呢?

首先需要下载支持你的平台的Node.js,可能是Linux或者Windows版本(是的!Node.js还提供了Windows的版本!)。因为每个版本的安装方法和安装工具都有所不同,所以本书不在安装当前版本上花费时间。如果需要安装说明,可以浏览在线文档;如果还是失败了,可以通过Google或者其他搜索引擎查找其他人发布的相同问题的网页或者论坛帖子,然后找到解决方案。

1.1 Node和npm命令

写给PHP开发者的Node.js学习指南
安装完成后,你会发现运行Node.js非常简单,它主要由两部分组成:node和npm命令。

Node命令使用非常简单。尽管它有很多参数,但是一般情况下你只会给node传递一个参数,就是Node.js源文件的文件名。例如:


3556867ca928183db1336c8a5db86ab6f5d2f8fc

node命令会在源文件(本例中是hello.js)中解析Node.js代码,执行代码,完成后退出回到shell或者命令行。

注意到hello.js文件扩展名为.js。.js扩展名表示JavaScript。好处在于,以.js为扩展名的文件既可以是客户端JavaScript,也可以是服务器端Node.js代码。不过,尽管这两者都是用JavaScript,但是他们之间并没有其他共同之处了。客户端JavaScript代码需要服务于浏览器,而服务器端Node.js代码需要可执行node命令或者可以访问通过node命令运行的main Node.js代码。这导致了不必要的误解。

在一些Node.js项目中,客户端的JavaScript文件放在同一个文件夹中,比如client文件夹,而Node.js文件放在另一个文件夹,比如server。通过文件夹方案来分离客户端JavaScript文件和Node.js文件仍然会存在一些问题,因为很多代码编辑器在标题栏或者标签中只显示文件名而不是全路径。

所以,在我的项目中,对Node.js文件采用了.njs作为扩展名,对客户端JavaScript文件则保留.js作为扩展名。让我说得更清楚一点,.njs文件名并不是标准扩展名,至少,现在还不是(也许永远都不会)。我还用Google搜索了一下,一般做法是Node.js的扩展名为.js。为了避免一直混淆客户端和服务器端的JavaScript,我使用了.njs作为Node.js代码的扩展名,在PHP到Node.js移植过程中,我也建议这么做。

所以,我使用hello.njs代替之前的hello.js:


8273f4428b73b4e04f7ed34fc13ef0e3aff641e6

本书其余部分都会使用.njs作为Node.js文件扩展名。

简单的hello.njs文件内容为:


f9ef01a48a00b79e71712a0eaf138c058a35c411

如果你运行node hello.js,会在控制台输出“Hello world!”然后退出。

为了运行一个Web服务器,可以使用hellosvr.njs源文件:


8cce6b45b90df6f85777f0ce176e7d197adb225d

如果运行node hellosvr.njs,终端命令行会挂起。服务器必须一直运行,才能接受来自页面的请求并做出响应。

如果打开Firefox或者Chrome,在地址栏输入http://127.0.0.1:1337,就可以看到一个简单的页面,显示“Hello world!”。事实上,访问http://127.0.0.1:1337/index.html,或者http://127.0.0.1/abc,甚至是http://127.0.0.1/abc/def/ghi,都会看到同一个显示“Hello world!”的页面。因为我们现在的服务器对所有页面请求都做出同样的响应。

这段代码中重要的是第一行,使用Node.js 全局函数require()。Require()方法用于加载一个你想要使用的的Node.js模块。模块是指数据和方法的一个集合,提供了某个特定方面的功能。在本例中,Node.js的http模块用于提供HTTP服务器功能。

Node有很多内建的模块:http、https、fs、path、crypo、url、net、dgram、dns、tls和child_process。这些内建模块的功能随着版本变化也有不同。

从设计角度来讲,一个模块代表了一个命名空间(namespace)。命名空间是指加在数据或者函数引用之前的额外描述。比如,http是createServer()方法的命名空间。在Node.js中,命名空间就是一个对象。当http模块被加载时,require()方法返回一个对象并赋值给http变量,变量名并不一定非要是http,也可以是“xyzzybub”,如果是这样,服务器创建的方法就是xyzzybub.createServer()。

为什么需要有命名空间呢?为什么不直接把所有数据和方法都作为全局变量呢?

Node.js期望新的模块代表新的功能,比如访问MySQL数据库,应该由其他人开发然后在Node.js安装完成后集成在node命令中。而在这些模块中的数据和方法名可能各种各样,开发人员很可能不小心使用了别的开发人员在其他模块中使用的函数名。但是由于模块都存在于一个命名空间中,可以由命名空间来区分同名的函数。实际上,在之前的编程语言比如C++和JAVA的基础上,Node.js的一个重要改进就是允许模块的使用者自定义模块的命名空间,用户自己会将模块赋值给自定义的变量,比如http或者xyzzybub。

这些具有新功能的新模块可以看做是包(package)。包是指一个可以添加到node命令行但是不是默认集成到node的模块。模块和包的界线并不明显,可以理解为只是专业术语上的变化。

Npm(node package manager)命令可以为node添加新的package。

要安装一个package,首先使用Google或者其他搜索引擎找到你想要安装的那个npm package,大部分时候,都在GitHub上。另一种不同于搜索引擎的方式是使用npm search命令来查找想要安装的package。

设想一下我们需要一个Web服务器通过硬盘的文件提供静态页面,而不总是返回“Hello world!”。为了找到一个Node.js静态文件服务器模块,一个好的搜索关键字是“nodejs static file server”。或者直接使用“npm search static”、“npm seach file”或者“npm search server”,会列出npm package名字或者描述中包含“static”、“file”或者“server”的package。不管使用哪一种方法,你都会找到Alexis Sellier,a.k.a cloudhead,创建的非常流行的静态文件服务器模块,地址是:https://github. com/cloudhead/node-static。

可以用以下命令安装package(附加选项,比如-g或者--global,可以用于配置包的安装方式):


42bc3224d0c008c69640e7afcc9365295b99c5e4

npm命令会获取package,然后成功安装(希望是这样)。以下是安装成功的一些输出:


a6af64f1b64b80e66e158a3d4685f52eb13a4c7c

GET表示使用HTTP GET方法来尝试获取package。200表示HTTP GET方法返回“HTTP status 200 OK”,意味着获取文件成功。

现在有很多npm package,但是只有一部分非常流行,比如express、node-static、connect、sockets.io、underscore、async和optimist。

使用以下httpsvr.njs文件,来实现一个Web服务器提供静态页面:


ea179c8f4b11b814637f75ad0c733446c94cd5e2

这就是Node.js开发的基本过程。需要编辑器来创建或者修改包含Node.js代码的.njs文件。当需要新的功能而node中没有时,npm命令可以下载并安装包含所需功能的npm 包。node命令用于运行.njs文件来执行Node.js代码,然后可以测试和使用该Web应用。

现在,我们已经看到过3个Node.js服务器了:hello.njs、hellosvr.njs还有httpsvr.njs。这些源文件都很简单,不必关心它们是怎么创建的。可以用任何文本编辑器来创建这些文件。如果什么地方出错了,很容易直接编辑修改。

我们可以放心地假设你已经有了一个复杂的Web应用,有很多文件,成千上万行需要移植的PHP代码。移植会是一个冗长的按部就班的过程。

第一个步骤需要创建一个Node.js的样板文件用于保存新的Node.js代码,具体在第2章中描述。这个样板文件会被修改,用于响应用户发起的特定URL请求。这种转换是为了使Node.js服务器对客户端的响应方式与PHP服务器相同。为了做到这一点,需要修改Node.js样本文件来处理每个HTTP请求,并将请求转发到特定的Node.js代码段进行处理,这些Node.js代码段是之后用于在Node.js中实现特定PHP页面的功能。

第二个步骤是重构PHP代码,主要在第3章和第4章中介绍,使PHP更容易移植到Node.js,换句话说,使PHP代码对Node.js更友好。转换的过程可能有些让人吃惊,它不仅仅是维持现有的PHP代码状态不变,复制到一个Node.js文件,然后一行一行地将PHP代码转换为Node.js。PHP和Node.js代码都会同步改进并且添加新的特性,所以鉴于两种语言的不同工作方式,PHP和Node.js都需要保留一些各自的特性来克服这些差异,这是有意义的。PHP代码需要做一些重构,并且为了之后需要创建的Node.js代码的功能做出一些牺牲。在移植结束的时候,两个代码库看起来会非常相似,都使用一种混合元语言编写,PHP的一系列惯例和算法都很容易移植到Node.js。这种元语言会使两个代码库看起来有点奇怪,但是功能都是完备的,并且随着时间推移,维护和改进这两个代码库的开发人员会越来越熟悉和理解这种语言。即使你决定最终扔掉所有的PHP代码只使用Node.js,也最好先从重构PHP代码开始,将PHP和Node.js代码都移植到那种奇怪的元编程语言,然后扔掉PHP,最后再将混合语言的Node.js重构为纯Node.js。不管你的目标是什么,重构PHP代码是将任何PHP移植到Node.js过程的关键步骤。

第三步就是将PHP页面从PHP文件中复制到Node.js文件中。当然,Node.js服务器一定会挂掉,正在运行的node命令会立即退出,输出错误的堆栈信息。

第四步就是转换并修改新添加的Node.js文件,在剩下的章节中会介绍,然后就成为可以工作的Node.js代码了。最开始,Node.js服务器无法工作,并且立即退出、打印堆栈信息。堆栈追踪信息可以指出错误发生的地方,可能是由于部分PHP代码没有完全转换为Node.js代码或者转换错误。分析清楚问题之后,可以对整个Node.js文件使用后面章节介绍的转换技术。比如,第7章介绍了使用array()初始化数组的方式将PHP转换为Node.js对象的初始化方法,使用花括号({})。当Node.js服务器可以重新运行之后,可能可以运行,但是很可能又继续出错退出。最终,Node.js代码完善,服务器可以运行。

令人惊讶的是有相当多的PHP代码存在于Node.js代码文件中,但不会导致Node.js服务器运行出错退出。当你对转换过程更熟悉之后,你会发现PHP和Node.js有很多相似,没转换的PHP代码会被node命令解析,并在node运行中可以接收HTTP请求,直到真的需要执行一些PHP代码时才会失败。

一旦Node.js代码没有问题,服务器可以运行,就可以开始用客户端进行测试了。客户端一般都是浏览器,比如Firefox、Google Chrome。一般来说,使用客户端进行测试时,Node.js会在某个点上出错退出,然后你需要分析堆栈追踪信息,并做出修正。一段时间之后,你会形成一系列特定的测试用例,可以用于客户端执行以发现未定位的转换问题,或者通过这些测试确保服务器工作正常。

有时,也可以用可视化的比对工具来比较PHP和Node.js代码。通过在源PHP代码中一步步地查看,可以更容易地定位新的Node.js代码中的问题。这可以提醒你使用一些尚未使用但是需要的转换技术,也可以追踪转换过程并很好地控制该过程。

剩下的PHP到Node.js的转换过程就是将之前的步骤重复执行很多次,直到PHP代码都转换为Node.js,并且Node.js代码可以稳定地工作。根据PHP代码库的大小,转换过程可能耗时几个月,但是如果你下定决心,转换过程可以很快结束。

网友评论

登录后评论
0/500
评论
异步社区
+ 关注