澳门新浦京手机版Node.js入门开发指南中文版

网络正在处于一个日新月异的发展时代。服务器端开发人员在选择语言的时候非常困惑,有长期占主导地位的语言,例如C、Java和Perl,也有专注于web开发的语言,例如Ruby、Clojure和Go。只要你的项目运行良好,你的选择就显得没有那么重要了。

关于

本书致力于教会你如何用Node.js来开发应用,过程中会传授你所有所需的“高级”JavaScript知识。本书绝不是一本“Hello
World”的教程。

JavaScript与Node.js

澳门新浦京手机版 1

状态

你正在阅读的已经是本书的最终版。因此,只有当进行错误更正以及针对新版本Node.js的改动进行对应的修正时,才会进行更新。

本书中的代码案例都在Node.js 0.6.11版本中测试过,可以正确工作。

JavaScript与你

但是如何让这些新的web开发人员做出一个正确的选择呢?

读者对象

本书最适合与我有相似技术背景的读者:
至少对一门诸如Ruby、Python、PHP或者Java这样面向对象的语言有一定的经验;对JavaScript处于初学阶段,并且完全是一个Node.js的新手。

这里指的适合对其他编程语言有一定经验的开发者,意思是说,本书不会对诸如数据类型、变量、控制结构等等之类非常基础的概念作介绍。要读懂本书,这些基础的概念我都默认你已经会了。

然而,本书还是会对JavaScript中的函数和对象作详细介绍,因为它们与其他同类编程语言中的函数和对象有很大的不同。

抛开技术,我们先来聊聊你以及你和JavaScript的关系。本章的主要目的是想让你看看,对你而言是否有必要继续阅读后续章节的内容。

我不希望展开一场PHP、NodeJs两大阵营之间的战争,我将会对比这两种语言所在领域的发展状况:

本书结构

读完本书之后,你将完成一个完整的web应用,该应用允许用户浏览页面以及上传文件。

当然了,应用本身并没有什么了不起的,相比为了实现该功能书写的代码本身,我们更关注的是如何创建一个框架来对我们应用的不同模块进行干净地剥离。
是不是很玄乎?稍后你就明白了。

本书先从介绍在Node.js环境中进行JavaScript开发和在浏览器环境中进行JavaScript开发的差异开始。

紧接着,会带领大家完成一个最传统的“Hello
World”应用,这也是最基础的Node.js应用。

最后,会和大家讨论如何设计一个“真正”完整的应用,剖析要完成该应用需要实现的不同模块,并一步一步介绍如何来实现这些模块。

可以确保的是,在这过程中,大家会学到JavaScript中一些高级的概念、如何使用它们以及为什么使用这些概念就可以实现而其他编程语言中同类的概念就无法实现。

该应用所有的源代码都可以通过
本书Github代码仓库.

目录

  • 关于
    • 状态
    • 读者对象
    • 本书结构
  • JavaScript与Node.js
    • JavaScript与你
    • 简短申明
    • 服务器端JavaScript
    • “Hello World”
  • 一个完整的基于Node.js的web应用
    • 用例
    • 应用不同模块分析
  • 构建应用的模块
    • 一个基础的HTTP服务器
    • 分析HTTP服务器
    • 进行函数传递
    • 函数传递是如何让HTTP服务器工作的
    • 基于事件驱动的回调
    • 服务器是如何处理请求的
    • 服务端的模块放在哪里
    • 如何来进行请求的“路由”
    • 行为驱动执行
    • 路由给真正的请求处理程序
    • 让请求处理程序作出响应
      • 不好的实现方式
      • 阻塞与非阻塞
      • 以非阻塞操作进行请求响应
    • 更有用的场景
      • 处理POST请求
      • 处理文件上传
    • 总结与展望

如果你和我一样,那么你很早就开始利用HTML进行“开发”,正因如此,你接触到了这个叫JavaScript有趣的东西,而对于JavaScript,你只会基本的操作——为web页面添加交互。

  • PHP
    Rasmus
    Lerdorf在1994年创造出了PHP。它是由安装在web服务器(Apache、Ngix)上的组件运行的。PHP代码可以和HTML混合到一块。
    对于初学者就能很快写出很有价值的代码,这并不需要太多的练习。 这让PHP变得越来越流行,
    现在全球百分之八十的服务器上都在运行着PHP。全球四分之一的网站都在用的一个内容管理系统–WordPress,就是用PHP写的。
  • Node.js
    Ryan Dahl在2009年创造了Node.js。它是基于Google的V8
    JavaScript解释引擎(在Chrome浏览器里它负责执行客户端的JavaScript代码)。与其它语言不同的是Node.js内置了处理网络请求和响应的函数库,所以你不需要单独的服务器(Apache、Ngix)或者其他依赖。Node.js虽然很新但是很快就获得了极大的追捧。在很多的大公司都有在使用,例如:Microsoft,Yahoo,LinkedIn和PayPal。

JavaScript与Node.js

而你真正想要的是“干货”,你想要知道如何构建复杂的web站点 ——
于是,你学习了一种诸如PHP、Ruby、Java这样的编程语言,并开始书写“后端”代码。

我们所钟爱的C#、Java、Ruby、Python、Perl、Erlang、C++、Go、Dart、Scala、Haskell等等,它们呢?

如果文章里边比较了如上所有语言的各种参数,文章将会非常长,你还会读它么?你期望一个程序员了解所有的程序开发语言吗?这显然是不可能的。我主要对PHP和Node.js做了比较,主要原因如下:

  1. 首先它们之间值得比较。两者都是开放源码,都是致力于web开发,并且都可用于相似的项目。
  2. PHP已经发布了很久了,但是Node.js才刚刚兴起,并受到越来越多的关注。难道PHP的程序员应该相信Node.js的宣传?应该考虑转换语言?
  3. 我了解,热爱编程语言,自从20世纪90年代之后我就一直使用PHP和JavaScript,并且也有几年的Node.js的经验。除此之外我也涉猎了其他的技术,但是在这里我还不能对他们作出客观评价。

另外,对多少语言做比较不重要,因为总会有某些地方的某些人抱怨我没有提到他们语言。

JavaScript与你

抛开技术,我们先来聊聊你以及你和JavaScript的关系。本章的主要目的是想让你看看,对你而言是否有必要继续阅读后续章节的内容。

如果你和我一样,那么你很早就开始利用HTML进行“开发”,正因如此,你接触到了这个叫JavaScript有趣的东西,而对于JavaScript,你只会基本的操作——为web页面添加交互。

而你真正想要的是“干货”,你想要知道如何构建复杂的web站点 ——
于是,你学习了一种诸如PHP、Ruby、Java这样的编程语言,并开始书写“后端”代码。

与此同时,你还始终关注着JavaScript,随着通过一些对jQuery,Prototype之类技术的介绍,你慢慢了解到了很多JavaScript中的进阶技能,同时也感受到了JavaScript绝非仅仅是window.open()
那么简单。 .

不过,这些毕竟都是前端技术,尽管当想要增强页面的时候,使用jQuery总让你觉得很爽,但到最后,你顶多是个JavaScript用户,而非JavaScript开发者

然后,出现了Node.js,服务端的JavaScript,这有多酷啊?

于是,你觉得是时候该重新拾起既熟悉又陌生的JavaScript了。但是别急,写Node.js应用是一件事情;理解为什么它们要以它们书写的这种方式来书写则意味着——你要懂JavaScript。这次是玩真的了。

问题来了:
由于JavaScript真正意义上以两种,甚至可以说是三种形态存在(从中世纪90年代的作为对DHTML进行增强的小玩具,到像jQuery那样严格意义上的前端技术,一直到现在的服务端技术),因此,很难找到一个“正确”的方式来学习JavaScript,使得让你书写Node.js应用的时候感觉自己是在真正开发它而不仅仅是使用它。

因为这就是关键:
你本身已经是个有经验的开发者,你不想通过到处寻找各种解决方案(其中可能还有不正确的)来学习新的技术,你要确保自己是通过正确的方式来学习这项技术。

当然了,外面不乏很优秀的学习JavaScript的文章。但是,有的时候光靠那些文章是远远不够的。你需要的是指导。

本书的目标就是给你提供指导。

与此同时,你还始终关注着JavaScript,随着通过一些对jQuery,Prototype之类技术的介绍,你慢慢了解到了很多JavaScript中的进阶技能,同时也感受到了JavaScript绝非仅仅是window.open()那么简单。
.

SitePoint上的角逐

程序员会花费很多时间来提升他们自己的编程能力。一些人有编程语言之间的延伸能力,但是这些达到更高层次的人根据很多的因素来做出他们自己的选择。从主观方面来说,你将会推进并且捍卫你的技术决策。

SitePoint
Smackdowns并没有采取“选择适合你自己的,朋友”这样的观点。我将会根据个人的经验、要求和喜好提出建议。你可能不会同意所有的我所说的所有观点,这并不重要,重要的是你的意见将会给其他人做出更加明智的选择。

简短申明

业界有非常优秀的JavaScript程序员。而我并非其中一员。

我就是上一节中描述的那个我。我熟悉如何开发后端web应用,但是对“真正”的JavaScript以及Node.js,我都只是新手。我也只是最近学习了一些JavaScript的高级概念,并没有实践经验。

因此,本书并不是一本“从入门到精通”的书,更像是一本“从初级入门到高级入门”的书。

如果成功的话,那么本书就是我当初开始学习Node.js最希望拥有的教程。

不过,这些毕竟都是前端技术,尽管当想要增强页面的时候,使用jQuery总让你觉得很爽,但到最后,你顶多是个JavaScript用户,而非JavaScript开发者

评估方法

下面将会对 PHP 和 Node.js
进行十个轮次的比较。每个回合都会考量可以应用到任意 web
技术的常见的开发挑战。我们不会太深入讨论细节;很少有人会关心随机数生成器或数组排序的价值。

赢得最多回合的将会是优胜者。准备好了吗?开始较量吧。。。。。。

服务端JavaScript

澳门新浦京手机版,JavaScript最早是运行在浏览器中,然而浏览器只是提供了一个上下文,它定义了使用JavaScript可以做什么,但并没有“说”太多关于JavaScript语言本身可以做什么。事实上,JavaScript是一门“完整”的语言:
它可以使用在不同的上下文中,其能力与其他同类语言相比有过之而无不及。

Node.js事实上就是另外一种上下文,它允许在后端(脱离浏览器环境)运行JavaScript代码。

要实现在后台运行JavaScript代码,代码需要先被解释然后正确的执行。Node.js的原理正是如此,它使用了Google的V8虚拟机(Google的Chrome浏览器使用的JavaScript执行环境),来解释和执行JavaScript代码。

除此之外,伴随着Node.js的还有许多有用的模块,它们可以简化很多重复的劳作,比如向终端输出字符串。

因此,Node.js事实上既是一个运行时环境,同时又是一个库。

要使用Node.js,首先需要进行安装。关于如何安装Node.js,这里就不赘述了,可以直接参考官方的安装指南。安装完成后,继续回来阅读本书下面的内容。

然后,出现了Node.js,服务端的JavaScript,这有多酷啊?

第一轮:起步

创建一个“Hello
World”
web 页面有多快呢?在 PHP 中:

<?php
    echo 'Hello World!';
?>

这段代码可以放置在可以被 PHP 引擎解析的任意文件中–通常,是以 .php
为后缀的文件。在浏览器中输入 URL 跳转到文件即可。

不可否认,这不是全部。这段代码只能运行于安装了 PHP 的 web 服务器(PHP
有一个内置的服务器,尽管如此,最好还是使用一个更健壮的服务器)。大多数操作系统提供了服务器软件,如 windows
上的 IIS,Mac 和 Linux 上的
Apache,尽管它们需要启动和配置。通常使用提前构建的安装程序,如 XAMPP
或虚拟机镜像(如 Vagrant)。一种更简单的方式:上传你的文件到任意的 web
主机。

对比而言,安装 Node.js
轻而易举。你可以 下载安装程序 或者 使用包管理器。
接下来让我们在 hello.js 中创建 web 页面:

var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World!');
}).listen(3000, '127.0.0.1');

在浏览器中访问   之前,你需要在终端输入 node
hello.js 来启动应用程序 。通过上面的五行代码,我们已经创建了一个小型的
web 服务器,尽管这很令人吃惊,但是即便拥有很强客户端 JavaScript
经验的人也很难理解。

PHP 在概念上更简单所以赢得本轮。稍微懂得一些 PHP
声明的人就可以开发一些有用的东西。PHP 有更多的软件依赖,但是 PHP
的概念对于新手来说不那么繁琐。

懂一些 JavaScript 和开发 Node.js 应用是两回事儿,Node.js
开发方法和大多数服务端技术不同,你需要先弄明白一些相当复杂的概念,比如关闭和回调函数。

“Hello World”

好了,“废话”不多说了,马上开始我们第一个Node.js应用:“Hello World”。

打开你最喜欢的编辑器,创建一个helloworld.js文件。我们要做就是向STDOUT输出“Hello
World”,如下是实现该功能的代码:

console.log("Hello World");

保存该文件,并通过Node.js来执行:

node helloworld.js

正常的话,就会在终端输出Hello World

好吧,我承认这个应用是有点无趣,那么下面我们就来点“干货”。

澳门新浦京手机版 2

于是,你觉得是时候该重新拾起既熟悉又陌生的JavaScript了。但是别急,写Node.js应用是一件事情;理解为什么它们要以它们书写的这种方式来书写则意味着——你要懂JavaScript。这次是玩真的了。

第二轮:帮助和支持

没有官方文档和资源(课程,论坛,堆栈溢出)的帮助你必将举步维艰。 PHP
在本轮轻易胜出,她有大量的指南和二十年的
Q&A。无论你想做什么,总会有人在你之前已经面对过同样的问题。

Node.js 拥有很好的文档,但是更加年轻,能提供的帮助较 PHP
也少。JavaScript 在市面上的时间和 PHP
一样久,但是主要的帮助都是针对浏览器开发的,那基本没啥帮助。

问题来了:
由于JavaScript真正意义上以两种,甚至可以说是三种形态存在(从中世纪90年代的作为对DHTML进行增强的小玩具,到像jQuery那样严格
意义上的前端技术,一直到现在的服务端技术),因此,很难找到一个“正确”的方式来学习JavaScript,使得让你书写Node.js应用的时候感觉
自己是在真正开发它而不仅仅是使用它。

第三回合: 语言语法

声明与结构是不是符合逻辑而且简单好用?

不像一些语言跟框架,PHP
不会限制你按特定的方式编写,具体怎么搞随你。你可以从几行的程序开始,然后添加些方法,进而写一些简单的
PHP4 模式的对象,最后编写优雅的面向对象的 MVC 模式 PHP5+
的应用。你的代码开始可能比较混乱,但也能工作,而且会随着理解的深入越写越好。

PHP
的语法在版本间可能略有调整,但是向后兼容一般都做得很好。但不幸的是,这也导致了一个问题:PHP
很混乱。例如,怎么统计一个字符串中字符的个数?是 count?str_len? 还是
strlen?亦或 mb_strlen?PHP
有数以百记的函数,而且命名规则也也不完全一致。可以试试不查文档写几行代码。

JavaScript
相对就简单些,只有几十个核心声明。不过语法就经常被开发者喷了,因为它的原型化对象模型看起来平易近人,实际上却不是。而且各种数学错误(0.1+0.2
!= 0.3)以及类型转换的混乱(’4′ + 2 == ’42′ 和 ’4′ – 2 ==
2)也招致不少抱怨,但这些情况世界很少导致什么问题,多数语言都有这种借口。

PHP 有他的优点,但是这回合我判 Node.js 胜。理由如下:

  1. JavaScript 是世界上最难理解的语言 —
    但是,当哪天你顿悟以后,概念一通,就会发现其他语言都太过笨拙了。
  2. JavaScript 代码比 PHP 简洁。例如,你再不需要跟 JSON 转来转去—— UTF-8
    也不用
  3. 全栈工程师可以同时在客户端与服务端使用
    JavaScript 。大脑不需要来回切换。
  4. 深入理解 JavaScript 会让你更想用它,但是 PHP 不是这样。

因为这就是关键:
你本身已经是个有经验的开发者,你不想通过到处寻找各种解决方案(其中可能还有不正确的)来学习新的技术,你要确保自己是通过正确的方式来学习这项技术。

第四轮:开发工具

两种技术都有一些很好的编辑器,集成开发环境,调试器,验证器和其他工具。我认为这是平局,但是这里有一些工具给
Node.js 些许优势:NPM-包管理器。 NPM
允许你安装和管理依赖,设置配置变量,定义脚本和其他。

PHP 的 Composer 项目受 NPM 激发,在有些方面更强。但是,PHP
在默认情况想不提供,活动库较小,在社区的影响更小。

Grunt 和 Gulp 之类革新了开发方法的构建工具的壮大,NPM
也有一部分功劳。有时候 PHP 开发者也许想要/需要安装 node.js,这不是倒退。

当然了,外面不乏很优秀的学习JavaScript的文章。但是,有的时候光靠那些文章是远远不够的。你需要的是指导。

第五轮:环境

技术可以在哪使用和部署?支持哪些平台和生态系统?网页开发者经常需要开发一些并不完全针对网页的应用,比如构建工具,迁移工具,数据库转换脚本等。

PHP 有办法开发桌面应用和命令行工具,但是你不会使用他们。本质上,PHP
是一个服务端技术,他很擅长该领域,但是很少延伸到这之外。

若干年前,JavaScript
被认为限制很多,有一些边缘技术,但是他的主战场还是浏览器。Node.js
已经改变了这一感觉并井喷出了很多 JavaScript 项目,你可以在任何地方使用
JavaScript:浏览器,服务器,终端,桌面甚至嵌入式系统,这使得 JavaScript
无处不在。

本书的目标就是给你提供指导。更多学习资料请点击此处

第六轮:集成

开发技术很受限制,除非他们能与数据库和驱动集成。PHP 在这方面很强,PHP
面世已经很多年,他的扩展使他能和拥有主流或冷门的 API 的服务器直接通讯。

Node.js
正在迎头直追,但是你也许会为某些老旧,冷门的技术寻找成熟集成组件而头疼。

简短申明

第七轮:托管和部署

部署你绚丽新应用到在线网页服务器有多容易?这是 PHP
的另一次完胜。随机联系某个网页托管公司你可以找到对主要的 PHP
支持,也许还免费附送 MySQL。对于沙盒,PHP
被认为更简单,有风险的扩展可以被禁用。

Node.js
是个不同的野兽,服务端的应用永远运行。你需要一台物理/虚拟/云或定制的服务器环境,最好有
root
权限,这对有些服务器来说遥不可及,特别是那些共享的服务器,你有可能让整台服务器宕机。

Node.js 托管将会变得简单,但是我认为他永远没法像 FTP 上传一些 PHP
文件那么方便。

业界有非常优秀的JavaScript程序员。而我并非其中一员。

第八轮:性能

PHP 很勤快,有很多项目跟选项可以使它跑得更快。即使那些对性能要求很严苛的
PHP 开发者也几乎不会担心速度问题, 但是 Node.js 性能通常更好一些。
当然,性能很大程度上决定于开发团队的经验以及是否上心, 但是 Node.js
还是有如下几条优势的:

更少的依赖

所有对 PHP 应用的请求都必须经过一个 WEB 服务器的路由,来启动 PHP
的解释器运行 PHP 代码。Node.js 不需要这些依赖,
而且你基本一定会使用一个带服务器的框架,像 Express,他很轻量,很好的扮演你应用的一部分。

更小更快的解释器

Node.js 的解释器比 PHP 的更小更灵活。
他并不受旧版语言遗留兼容问题的拖累,而且 Google 在 V8
引擎性能改善上出了大力。

应用永久在线

PHP 遵循标准客户端-服务端模型。 每个页面请求都会初始化应用;
你读取配置参数、连接数据库、读取信息、渲染 HTML。Node.js
应用持久运行,只需要启动一次。例如,你可以创建一个单独数据连接对象,然后所求请求一起复用。公认的,PHP
也有一些途径来实现,比如使用 Memcached ,但是这已经不是语言的标准特性了。

我就是上一节中描述的那个我。我熟悉如何开发后端web应用,但是对“真正”的JavaScript以及Node.js,我都只是新手。我也只是最近学习了一些JavaScript的高级概念,并没有实践经验。

事件驱动,无阻塞 I/O

PHP 跟其他多数服务端语言采用阻塞执行的模型。
当你执行一个命令,比如从数据库取数据,那么必须等这个指令执行完成后,才会执行下面的内容。 Node.js
通常不会等的。 取而代之的是,
你需要提供一个回调函数,这个函数当指令执行完后会被调用一次。例如:

// fetch records from a NoSQL database
DB.collection('test').find({}).toArray(process);
console.log('finished');

// process database information
function process(err, recs) {
    if (!err) {
        console.log(recs.length + ' records returned');
    }
}

这个例子中, 控制台会先输出‘finished’,然后输出‘N records
returned’,因为 process 函数是所有数据返回的时候才被调用的。 换句话说,当解释器在其它进程处理的时候可以干些别的事情。

注意情况比较复杂,还有几个警告:

  • Node.js/JavaScript 只能在单线程上运行,但是大多数 web
    服务器都是多线程,而且并发的处理请求。
  • 一个用户长时间运行的 JavaScript
    处理会阻止其它用户的代码执行,除非拆分任务或者使用Web
    Workers。
  • 基准测试是主观的和有缺陷的;可以找到一些例子 Node.js
    比较好,而一些相对的例子 PHP 比较好
    。程序员只是在尝试证明他们的信仰!
  • 书写异步的事件驱动的代码非常复杂,非常有挑战性。

我只能从我的经验来讲: 我的 Node.js 应用要明显比 PHP
的同等应用要快。你的可能不是,但是不试是永远不会知道的。

因此,本书并不是一本“从入门到精通”的书,更像是一本“从初级入门到高级入门”的书。

第九轮:开发者激情

这会超出”常见网页开发挑战“这样的目标,但是这很重要。如果你恐惧每天写代码,那你无所谓哪门语言更好。

很难为此做出比较但是一些 PHP 开发者对 PHP
这门语言很有激情。你最近一次读到让你走心的 PHP
文章或幻灯片是什么时候?也许已无需再说?可能是更低的曝光度?或者我没找对地方?PHP7
有一些新的功能,但是该技术已经原地踏步很多年了,虽说如此,很少有开发人员对PHP发牢骚。

JavaScript
分离了社区,有人爱也有人恨,一些程序员在中间犹豫不决,经管如此,对
Node.js
的反馈大多积极,她正处于风口浪尖,一部分原因是因为她很新,赞誉不一定持续。目前,Node.js
赢得本轮。

如果成功的话,那么本书就是我当初开始学习Node.js最希望拥有的教程。

第十轮:前景

您选择采用哪种服务端语言并不重要;即使她不再被更新也会照样继续工作(yay
ColdFusion!)尽管使用量上趋于稳定但是很多人依然使用
PHP,我打包票她还能再坚挺二十年。

Node.js
崛起得很迅速,她提供了一种现代的开发方式,使用和客户端开发一样的语法同时支持
HTML5
变革式的特征,比如网络套接字和服务端发送事件。尽管大家对该语言的分叉函数有些争议,但是Node.js的使用量还是呈指数级增长。

Node.js 势必会蚕食 PHP
的市场份额,但是我不认为她能完全取而代之。两种技术都有光辉的未来。我宣布本轮平手。

服务端JavaScript

最终赢家

最终分数:Node.js 赢得5轮,PHP
赢得4轮,一轮平手。原以为会倒向其中一方,结果比我预想的更中庸一些。

Node.js
有一定的学习曲线,对新手来说不够理想但是她赢得了本次对决。而且,如果你是位喜欢该语言的靠谱的
JavaScript 程序员,Node.js
不会让你失望。她更新潮而且提供自己网页开发的体验,你不会思念 PHP。

但是不要贬低 PHP,PHP 依然有活力,你不该因为 Node.js
快一些,新一些或新潮一些就去紧跟 Node.js 潮流。PHP
易学而且依然支持专业的编程技巧,帮助无处不在而且开发简单。甚至死忠的
Node.js 开发者也不得不在简单网站和应用时考虑使用 PHP。

我的建议是:评估选项,根据你的需求来选择一门语言,这比本文这样的”对比“文章靠谱得多。

JavaScript最早是运行在浏览器中,然而浏览器只是提供了一个上下文,它定义了使用JavaScript可以做什么,但并没有“说”太多关于
JavaScript语言本身可以做什么。事实上,JavaScript是一门“完整”的语言:
它可以使用在不同的上下文中,其能力与其他同类语言相比有过之而无不及。

Node.js事实上就是另外一种上下文,它允许在后端(脱离浏览器环境)运行JavaScript代码。

要实现在后台运行JavaScript代码,代码需要先被解释然后正确的执行。Node.js的原理正是如此,它使用了Google的V8虚拟机
(Google的Chrome浏览器使用的JavaScript执行环境),来解释和执行JavaScript代码。

除此之外,伴随着Node.js的还有许多有用的模块,它们可以简化很多重复的劳作,比如向终端输出字符串。

因此,Node.js事实上既是一个运行时环境,同时又是一个库。

要使用Node.js,首先需要进行安装。关于如何安装Node.js,这里就不赘述了,可以直接参考官方的安装指南。安装完成后,继续回来阅读本书下面的内容。

“Hello World”

好了,“废话”不多说了,马上开始我们第一个Node.js应用:“Hello World”。

打开你最喜欢的编辑器,创建一个helloworld.js文件。我们要做就是向STDOUT输出“Hello
World”,如下是实现该功能的代码:

console.log(“Hello World”);

保存该文件,并通过Node.js来执行:

node helloworld.js

正常的话,就会在终端输出Hello World

好吧,我承认这个应用是有点无趣,那么下面我们就来点“干货”。

一个完整的基于Node.js的web应用

用例

我们来把目标设定得简单点,不过也要够实际才行:

用户可以通过浏览器使用我们的应用。

当用户请求http://domain/start时,可以看到一个欢迎页面,页面上有一个文件上传的表单。

用户可以选择一个图片并提交表单,随后文件将被上传到http://domain/upload,该页面完成上传后会把图片显示在页面上。

差不多了,你现在也可以去Google一下,找点东西乱搞一下来完成功能。但是我们现在先不做这个。

更进一步地说,在完成这一目标的过程中,我们不仅仅需要基础的代码而不管代码是否优雅。我们还要对此进行抽象,来寻找一种适合构建更为复杂的Node.js应用的方式。

应用不同模块分析

我们来分解一下这个应用,为了实现上文的用例,我们需要实现哪些部分呢?

我们需要提供Web页面,因此需要一个HTTP服务器

对于不同的请求,根据请求的URL,我们的服务器需要给予不同的响应,因此我们需要一个路由,用于把请求对应到请求处理程序(request
handler)

当请求被服务器接收并通过路由传递之后,需要可以对其进行处理,因此我们需要最终的请求处理程序

路由还应该能处理POST数据,并且把数据封装成更友好的格式传递给请求处理入程序,因此需要请求数据处理功能

我们不仅仅要处理URL对应的请求,还要把内容显示出来,这意味着我们需要一些视图逻辑供请求处理程序使用,以便将内容发送给用户的浏览器

最后,用户需要上传图片,所以我们需要上传处理功能来处理这方面的细节

我们先来想想,使用PHP的话我们会怎么构建这个结构。一般来说我们会用一个Apache
HTTP服务器并配上mod_php5模块。

从这个角度看,整个“接收HTTP请求并提供Web页面”的需求根本不需要PHP来处理。

不过对Node.js来说,概念完全不一样了。使用Node.js时,我们不仅仅在实现一个应用,同时还实现了整个HTTP服务器。事实上,我们的Web应用以及对应的Web服务器基本上是一样的。

听起来好像有一大堆活要做,但随后我们会逐渐意识到,对Node.js来说这并不是什么麻烦的事。

现在我们就来开始实现之路,先从第一个部分–HTTP服务器着手。

构建应用的模块

一个基础的HTTP服务器

当我准备开始写我的第一个“真正的”Node.js应用的时候,我不但不知道怎么写Node.js代码,也不知道怎么组织这些代码。

我应该把所有东西都放进一个文件里吗?网上有很多教程都会教你把所有的逻辑都放进一个用Node.js写的基础HTTP服务器里。但是如果我想加入更多的内容,同时还想保持代码的可读性呢?

实际上,只要把不同功能的代码放入不同的模块中,保持代码分离还是相当简单的。

这种方法允许你拥有一个干净的主文件(main
file),你可以用Node.js执行它;同时你可以拥有干净的模块,它们可以被主文件和其他的模块调用。

那么,现在我们来创建一个用于启动我们的应用的主文件,和一个保存着我们的HTTP服务器代码的模块。

在我的印象里,把主文件叫做index.js或多或少是个标准格式。把服务器模块放进叫server.js的文件里则很好理解。

让我们先从服务器模块开始。在你的项目的根目录下创建一个叫server.js的文件,并写入以下代码:

var http = require(“http”);

http.createServer(function(request, response){

response.writeHead(200,{“Content-Type”:”text/plain”});

response.write(“Hello World”);

response.end();

}).listen(8888);

搞定!你刚刚完成了一个可以工作的HTTP服务器。为了证明这一点,我们来运行并且测试这段代码。首先,用Node.js执行你的脚本:

node server.js

接下来,打开浏览器访问http://localhost:8888/,你会看到一个写着“Hello
World”的网页。

这很有趣,不是吗?让我们先来谈谈HTTP服务器的问题,把如何组织项目的事情先放一边吧,你觉得如何?我保证之后我们会解决那个问题的。

分析HTTP服务器

那么接下来,让我们分析一下这个HTTP服务器的构成。

第一行请求(require)Node.js自带的http模块,并且把它赋值给http变量。

接下来我们调用http模块提供的函数:createServer。这个函数会返回一个对象,这个对象有一个叫做listen的方法,这个方法有一个数值参数,指定这个HTTP服务器监听的端口号。

咱们暂时先不管http.createServer的括号里的那个函数定义。

我们本来可以用这样的代码来启动服务器并侦听8888端口:

var http = require(“http”);

var server = http.createServer();

server.listen(8888);

这段代码只会启动一个侦听8888端口的服务器,它不做任何别的事情,甚至连请求都不会应答。

最有趣(而且,如果你之前习惯使用一个更加保守的语言,比如PHP,它还很奇怪)的部分是createSever()的第一个参数,一个函数定义。

实际上,这个函数定义是createServer()的第一个也是唯一一个参数。因为在JavaScript中,函数和其他变量一样都是可以被传递的。

进行函数传递

举例来说,你可以这样做:

function say(word){

console.log(word);

}

function execute(someFunction, value){

someFunction(value);

}

execute(say,”Hello”);

请仔细阅读这段代码!在这里,我们把say函数作为execute函数的第一个变量进行了传递。这里返回的不是say的返回值,而是say本身!

这样一来,say就变成了execute中的本地变量someFunction,execute可以通过调用someFunction()(带括号的形式)来使用say函数。

当然,因为say有一个变量,execute在调用someFunction时可以传递这样一个变量。

我们可以,就像刚才那样,用它的名字把一个函数作为变量传递。但是我们不一定要绕这个“先定义,再传递”的圈子,我们可以直接在另一个函数的括号中定义和传递这个函数:

function execute(someFunction, value){

someFunction(value);

}

execute(function(word){ console.log(word)},”Hello”);

我们在execute接受第一个参数的地方直接定义了我们准备传递给execute的函数。

用这种方式,我们甚至不用给这个函数起名字,这也是为什么它被叫做匿名函数

这是我们和我所认为的“进阶”JavaScript的第一次亲密接触,不过我们还是得循序渐进。现在,我们先接受这一点:在JavaScript中,一个
函数可以作为另一个函数接收一个参数。我们可以先定义一个函数,然后传递,也可以在传递参数的地方直接定义函数。

函数传递是如何让HTTP服务器工作的

带着这些知识,我们再来看看我们简约而不简单的HTTP服务器:

var http = require(“http”);

http.createServer(function(request, response){

response.writeHead(200,{“Content-Type”:”text/plain”});

response.write(“Hello World”);

response.end();

}).listen(8888);

现在它看上去应该清晰了很多:我们向createServer函数传递了一个匿名函数。

用这样的代码也可以达到同样的目的:

var http = require(“http”);

function onRequest(request, response){

response.writeHead(200,{“Content-Type”:”text/plain”});

response.write(“Hello World”);

response.end();

}

http.createServer(onRequest).listen(8888);

也许现在我们该问这个问题了:我们为什么要用这种方式呢?

基于事件驱动的回调 实在太多,有兴趣的朋友可点击阅读全文

发表评论

电子邮件地址不会被公开。 必填项已用*标注