Node即学即用(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-14 09:20:29

点击下载

作者:[英]TomHughes-Croucher MikeWilson著

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Node即学即用

Node即学即用试读:

前言

介绍

Node.js正迅速成为Web开发社区里最有影响力的技术。本书的目标是让开发人员有效地了解如何入手试用Node。

本书读者应该对JavaScript及编程有一定程度的了解。除了详细介绍Node提供的API外,我们还将花大量篇幅来介绍服务器事件驱动开发的重要概念。

通过阅读本书,你不但能够了解Node平台本身,还能掌握Node为快速高效地构建高扩展性网站和服务所提供的多个重要模块。

排版约定

本书使用了下列排版约定。

•楷体

表示新术语。

•等宽字体

表示程序片段,也表示在正文中出现的变量、函数名、数据库、数据类型、环境变量、语句和关键字等。

•加粗等宽字体

表示用户的输入。

这个图标表明提示、建议或一般注记。

这个图标表示警告或警示。

使用代码示例

本书用于帮助你完成工作。通常,你可以在程序或文档中使用本书提供的代码。除非你重新发布我们的大量代码,否则不需要联系我们来获得许可。比如,在程序中使用本书代码的一些片段是无需我们许可的,但是出售或再分发O’Reilly的图书示例光盘显然是需要授权的。引用本书或引用示例代码来回答问题是不需要授权的,但是将本书的大量示例代码整合到你自己的产品文档必须得到授权。

我们希望你在使用时声明引用信息,但不强求。引用信息通常包括书名、作者、出版社和ISBN。例如:“Node: Up and Running by Tom Hughes-Croucher and Mike Wilson(O’Reilly). Copyright 2012 Tom Hughes-Croucher and Mike Wilson, 978-1-449-39858-3.”

如果你认为对示例代码的使用需要授权,请通过邮箱permissions@oreilly.com联系我们。

Safari®在线图书

在线图书是应需而变的数字图书馆。它能够让你非常轻松地搜索7500多种技术性和创新性参考书以及视频,以便快速地找到需要的答案。

订阅后就可以访问在线图书馆内的所有页面和视频。可以在手机或其他移动设备上阅读,还能在新书上市之前抢先阅读,也能够看到还在创作中的书稿并向作者反馈意见。复制粘贴代码示例、放入收藏夹、下载部分章节、标记关键点、做笔记甚至打印页面等有用的功能可以节省大量时间。

这本书英文版也在其中。欲访问本书的英文版电子版,或者由O’Reilly或其他出版社出版的相关图书,请到http://my.safaribooksonline.com免费注册。

我们的联系方式

请将有关此书的意见及问题发给出版商:

美国:

O’Reilly Media, Inc.

1005 Gravenstein Highway North

Sebastopol, CA 95472

中国:

北京市西城区西直门南大街2号成铭大厦C座807室(100035)

奥莱利技术咨询(北京)有限公司

本书有一个Web页面,上面列出了勘误表、一些实例以及所有的附加信息。可以通过以下链接来访问这个页面:

http://oreil.ly/node_upandrunning

为本书提意见或者询问一些技术性问题,可以向以下地址发送邮件:

bookquestions@oreilly.com

更多与书籍、会议、资源中心以及O’Reilly网络有关的问题,都请参见O’Reilly的网站:

http://www.oreilly.com

致谢

http://www.oreilly.com

感谢我的编辑们。Simon,这是一个漫长的项目,感谢你天天陪伴着我。Andy,你对细节的专注让我印象深刻。

感谢Carols,你写作的动力和能力让我羡慕,你为我带来了许多灵感。

感谢Nicole和Sean,是你们帮我把握方向,让我保持进度。

感谢Ryan和Isaac,你们像教育孩子那样耐心,不停地回答我那些无休止的傻问题。

感谢Rosemarie,没有你,我不可能有今天的成绩。

感谢我的朋友们,特别是Yta、Emily、Eric、Gris、Sarah、Allan、Harold、Daniella和 Hipster Ariel,感谢你们听我发牢骚。此外,还要感谢无数给我鼓励、建议和反馈的人,没有你们,我无法完成此书。

感谢读者朋友,谢谢你们购买并阅读这本书,谢谢你们信任我。——Tom第一部分基础入门第1章 Node.js简介

Node功能强大,特别是它能在浏览器以外运行JavaScript。本书将阐述这一功能为何如此重要,以及使用Node的好处。首先来概述一下这些特性。

很多人将JavaScript用在前端网站应用开发上。Node.js将这一流行编程语言扩展到了更多的领域,特别是后端网站服务器开发。Node有几个重要的特性值得我们关注。

Node 是对高性能 V8 引擎的封装(V8 是 Google Chrome 浏览器的 JavaScript 引擎),通过提供一系列优化的API类库,使V8在浏览器之外依然能高效运行。比如,在服务器端开发程序常常需要处理二进制文件,JavaScript语言本身对此支持得不好,因此V8也如此,而Node的Buffer类库提供了轻松操作二进制数据的方法。使用Node,除了可以直接操作V8的JavaScript运行时状态,还能在开发上得到更多益处。

Node的一大特性是对高性能的追求。首先,V8采用了编译领域的一些最新技术,使得用JavaScript等高级语言编写的代码在运行效率上能够接近用C等底层语言编写的代码,并且开发成本有所降低。

其次,Node利用了JavaScript的事件驱动(event-driven)特性来构建高度可扩展的服务器程序。Node 采用了事件循环(event loop)架构,让开发高效的服务器程序变得简单和安全。对比其他构建高性能服务器的架构,Node既保证了性能,又降低了开发难度。这是一个极其重要的特性。大家都知道开发多线程并行程序很困难,而且非常容易出错。Node却巧妙地回避了这一难题,并且保持着令人惊讶的高性能。当然,任何方法都存在利弊得失,在后续章节中,将会详细讨论Node在这其中是如何取舍的。

Node提供了一系列“非阻塞”函数库来支持事件循环特性。比如,把文件系统或数据库操作封装成事件驱动形式的函数接口。当对文件系统发起请求时,程序不需要闲置等待硬盘把文件读取出来。就像在浏览器中onclick事件被触发后会自动调用代码一样,非阻塞函数会在它获得文件内容后通知Node中的程序。这种方式让访问慢资源变得简单可扩展,这对JavaScript程序员来说可谓驾轻就熟,甚至普通人也很容易掌握。

Node的强大特性还包括能在服务器端运行JavaScript,尽管这样的特性并非Node所独有。如果想在主流浏览器上运行自己的应用,我们除了JavaScript之外没有什么其他选择。那么要想同一份代码在浏览器客户端和服务器间共享,也只能选择JavaScript。现在出现了越来越多用JavaScript编写的复杂网页应用(如Gmail),如果能把越多的代码共享到服务器上运行,那么开发的成本也会越低。Node为服务器端共享网页的JavaScript代码铺平了道路,这是PHP、Java、Ruby或Python等其他编程语言无法提供的。虽然也有其他平台提供了在服务器端使用JavaScript的手段,但Node已经先声夺人,迅速成为这个领域的主流平台。

除了可以用Node现有的库来构建应用外,开发者也可以轻松为其扩展新的库,这实在令人欣喜。正因为Node很容易扩展,在Node项目对外发布后,其社区便迅速涌现出大量扩展库。其中许多是连接数据库或其他软件的驱动接口,还有相当一部分是独立有用的软件。

Node社区也是非常值得称赞的。虽然其社区非常年轻,但已经罕见地受到许多开发者的热情关注。初学者和专家们都聚集在此项目上,使用它并反馈贡献到社区中,致力于把Node社区建设成每个人都能够在其中快乐地探索、分享知识并获得支持的地方。1.1 安装Node.js

安装Node.js是极其简单的事情。Node能够运行在Windows、Linux、Mac,以及Solaris和BSD等其他POSIX系统上。Node.js能够在以下两个地址获得:项目官方主页(http://nodejs.org)和GitHub代码库(http://github.com/joyent/node)。你可以优先选择Node主页上提供的稳定发布版。包含最新特性的版本托管在GitHub上,供核心开发团队使用。任何人想获得一份拷贝也能从GitHub上下载。虽然这些新特性通常很炫,但它们没有稳定版本那么可靠。

让我们从安装Node.js开始。首先要从Node主页下载最新发布的版本。在Node主页上,找到下载的链接。本书印刷时的稳定发布版[1]本是0.6.13 。Node主页提供了Windows和Mac的安装程序,以及源代码包。如果你在使用Linux,可以选择从源代码安装,也可以使用常见的包管理程序(apt-get、yum等)。

Node.js版本号依照C的习惯:主版本.次版本.补丁。稳定版本的次版本号是偶数,开发版本的次版本号是奇数。虽然不知道Node什么时候会到达1.0版本,但可以认定是在Windows和Unix版本合并成一个版本同时发布时。

如果你使用安装包,可以直接跳到1.2节。若你采用源代码安装,需要首先进行解压。使用tar命令,带上xzf参数。x参数表示解压(而不是压缩),z参数告诉tar用GZIP算法进行解压,f表示根据最后一个参数的文件名来解压(见例1-1)。

例1-1 代码解压

enki:Downloads $ tar xzf node-v0.6.6.tar.gz

enki:Downloads $ cd node-v0.6.6

enki:node-v0.6.6 $ ls

AUTHORS  Makefile  common.gypi  doc  test

BSDmakefile Makefile-gyp configure  lib  tools

ChangeLog README.md  configure-gyp node.gyp vcbuild.bat

LICENSE  benchmark  deps   src  wscript

enki:node-v0.6.6 $

下一步是根据你的系统进行配置。Node.js安装采用configure/make方法。configure程序将扫描你的系统,查找Node依赖库的路径。Node通常需要很少的依赖库。安装需要 Python 2.4 或更高版本,如果你想使用传输层安全(TLS)或加密(如SHA1),Node将需要OpenSSL开发库。运行configure程序将提示你缺少哪些依赖库(参见例1-2)。

例1-2 Node安装的配置

enki:node-v0.6.6 $ ./configure

Checking for program g++ or c++   : /usr/bin/g++

Checking for program cpp    : /usr/bin/cpp

Checking for program ar     : /usr/bin/ar

Checking for program ranlib    : /usr/bin/ranlib

Checking for g++      : ok

Checking for program gcc or cc   : /usr/bin/gcc

Checking for gcc      : ok

Checking for library dl     : yes

Checking for openssl     : not found

Checking for function SSL_library_init : yes

Checking for header openssl/crypto.h : yes

Checking for library util    : yes

Checking for library rt     : not found

Checking for fdatasync(2)with c++  : no

'configure' finished successfully(0.991s)

enki:node-v0.6.6 $

接着是运行make来编译项目(例1-3)。这将在我们一直使用的源代码文件夹下编译出可执行的二进制文件。Node会在编译过程中列出当前进行到第几步,以便查看。

例1-3 运行make来编译

enki:node-v0.6.6 $ make

Waf: Entering directory '/Users/sh1mmer/Downloads/node-v0.6.6/out'

DEST_OS: darwin

DEST_CPU: x64

Parallel Jobs: 1

Product type: program

[ 1/35] copy: src/node_config.h.in -> out/Release/src/node_config.h

[ 2/35] cc: deps/http_parser/http_parser.c -> out/Release/deps/http_

parser/http_parser_3.o

/usr/bin/gcc -rdynamic -pthread -arch x86_64 -g -O3 -DHAVE_OPENSSL=1 -D_LARGEFILE_SOURCE ...

[ 3/35] src/node_natives.h: src/node.js lib/dgram.js lib/console.js lib/

buffer.js ...

[ 4/35] uv: deps/uv/include/uv.h -> out/Release/deps/uv/uv.a

...

f: Leaving directory '/Users/sh1mmer/Downloads/node-v0.6.6/out'

'build' finished successfully(2m53.573s)

-rwxr-xr-x 1 sh1mmer staff 6.8M Jan 3 21:56 out/Release/node

enki:node-v0.6.6 $

最后一步是用make install来安装。首先,例1-4演示了如何为系统下全部用户安装Node程序。这需要你有root账户或者有运行sudo的权限。

例1-4 为系统下全部用户安装Node

enki:node-v0.6.6 $ sudo make install

Password:

Waf: Entering directory '/Users/sh1mmer/Downloads/node-v0.6.6/out'

DEST_OS: darwin

DEST_CPU: x64

Parallel Jobs: 1

Product type: program

* installing deps/uv/include/ares.h as /usr/local/include/node/ares.h

* installing deps/uv/include/ares_version.h as /usr/local/include/node/ares_version.h

* installing deps/uv/include/uv.h as /usr/local/include/node/uv.h

...

* installing out/Release/src/node_config.h as /usr/local/include/node/node_config.h

Waf: Leaving directory '/Users/sh1mmer/Downloads/node-v0.6.6/out'

'install' finished successfully(0.915s)

enki:node-v0.6.6 $

如果你想只安装到本地用户,或是不使用sudo命令,需要在运行configure的时候加上--prefix参数,指定路径来代替默认安装(例1-5)。

例1-5 安装到本地用户

enki:node-v0.6.6 $ mkdir ~/local

enki:node-v0.6.6 $ ./configure --prefix=~/local

Checking for program g++ or c++   : /usr/bin/g++

Checking for program cpp    : /usr/bin/cpp

...

'configure' finished successfully(0.501s)

enki:node-v0.6.6 $ make && make install

Waf: Entering directory '/Users/sh1mmer/Downloads/node-v0.6.6/out'

DEST_OS: darwin

DEST_CPU: x64

...

* installing out/Release/node as /Users/sh1mmer/local/bin/node

* installing out/Release/src/node_config.h as /Users/sh1mmer/local/include/node/...

Waf: Leaving directory '/Users/sh1mmer/Downloads/node-v0.6.6/out'

'install' finished successfully(0.747s)

enki:node-v0.6.6 $1.2 开始写代码

本节将介绍一些Node开发的基础内容,为进一步学习做准备。1.2.1 Node REPL

Node是服务器程序,人们常常难以理解它也有和Perl、Python、Ruby一样的运行时环境。所以通常我们称Node.js为“服务器端的JavaScript”,但这不能完全描述Node.js本身。了解Node.js的最佳方法是使用其提供的REPL模式(Read-Evaluate-Print-Loop,输入-求值-输出-循环),即交互式命令行解析器,它非常适合检验和学习Node.js。你可以在Node命令行解析器中试验本书提供的代码片段。此外,因为Node是对V8的封装,所以Node命令行解析器也是用来轻松测试JavaScript的理想方法。同时,当你想运行一个Node程序时,可以用任何你喜爱的文本编辑器写好并保存成文件,然后运行 node filename.js。命令行解析器是极佳的学习和探索工具,但我们不会将其用在产品程序中。

让我们启动Node命令行解析器,来个热身,试验一下JavaScript吧(参见例1-6)。在你的系统中打开命令行终端。我正使用Mac系统的自定义命令行环境,所以你的系统提示可能会有所不同,但使用的命令应该是一样的。

例1-6 启动Node命令行解析器并尝试测试JavaScript

$Enki:~ $ node

> 3 > 2 > 1

false

> true == 1

true

> true === 1

false

第一行代码返回的结果为false。这个例子来自一个收集JavaScript诡异和奇特特性的网站 http://wtfjs.com。

拥有一个实时的开发环境,你就有了非常好的学习工具,但你还需要了解Node解析器的一些有用的功能,才能更好地使用它。它提供了以点号(.)开头的元命令。如.help会显示帮助菜单,.clear会清除当前运行的内容,.exit将退出Node解析器(见例1-7)。其中最有用的命令是.clear,它会清除内存中任何变量或闭包,而不需要重启解析器。

例1-7 使用Node解析器中的元命令

> console.log('Hello World');

Hello World

> .help

.clear Break, and also clear the local context.

.exit Exit the prompt

.help Show repl options

> .clear

Clearing context...

> .exit

Enki:~ $

使用解析器时,输入变量的名称就会在终端上显示其内容。Node会尝试智能地显示复杂对象,比如通过描述来反映对象的内部构造,而不是简单地将其当做普通对象来显示(见例1-8)。主要的例外是显示函数,并非解析器无法显示函数内容,而是因为函数通常都很长,如果解析器把函数都展开,很可能会导致刷屏。

例1-8 解析器设置并显示对象

Enki:~ $ node

> myObj = {};

{}

> myObj.list = ["a", "b", "c"];

[ 'a', 'b', 'c' ]

> myObj.doThat = function(first, second, third){ console.log(first); };

[Function]

> myObj

{ list: [ 'a', 'b', 'c' ]

, doThat: [Function]

}

>1.2.2 编写首个服务器程序

命令行解析器是我们学习和试验的好工具,而Node.js最主要的应用是服务器程序。设计Node.js的一个主要目的是提供高度可扩展的服务器环境。这是我们在本章开篇介绍过的Node和V8引擎有所区别的地方。Node除了用V8引擎来解析JavaScript外,还提供了高度优化的应用库,用来提高服务器效率。比如说,HTTP模块是专为快速非阻塞式HTTP服务器而用C重新编写的。让我们看一下Node采用 HTTP 服务器的“Hello World”经典例子(例 1-9)。

例1-9 “Hello World”Node.js Web服务器

var http = require('http');

http.createServer(function(req, res){

res.writeHead(200, {'Content-Type': 'text/plain'});

res.end('Hello World\n');

}).listen(8124, "127.0.0.1");

console.log('Server running at http://127.0.0.1:8124/');

这个示例代码首先通过require方法把HTTP库包含到程序中来。有许多语言都有包含其他库这一方法,Node用的是CommonJS模块风格。Node模块将在第8章详细介绍,当前需要了解的是,HTTP库所具有的功能已经赋给了http对象。

下一步,我们需要一个HTTP服务器。PHP等其他语言需要在类似Apache这样的服务器中运行,而Node和它们不同,因为Node本身就是Web服务器。但这同样意味着我们需要先创建该服务器。下一行代码调用HTTP模块的一个工厂模式方法(createServer)来创建新的HTTP服务器。新创建的HTTP服务器并没有赋值给任何变量,它只会成为存活在全局范围内的匿名对象。我们可以通过链式调用来初始化服务器,并告诉它监听在8124端口。

当调用createServer的时候,我们传了一个匿名函数作为参数。此函数绑定在新创建服务器的事件监听器上进行request事件处理。消息事件是JavaScript和Node的核心。在这个例子中,每当一个新的访问请求到达Web服务器,它都将调用我们指定的函数方法来处理。我们称这类方法为回调(callback)。因为每当一个事件发生时,我们将回调监听此事件的所有函数。

一个很恰当的类比是,你从书店预订一本书,等书到货时,书店会“回调”通知你去取。

例子中的回调函数有两个参数,一个是请求的对象(req),一个是响应的对象(res)。在回调函数中,我们调用了res对象的几个方法,这将修改响应结果。例1-9没有使用req对象,但你通常会需要同时使用请求和响应对象。

首先我们必须调用res.writeHead方法来设置HTTP响应头,否则就不能返回真实内容给客户端。我们设置状态代码为 200(表示 HTTP 状态代码“200 OK”),并且传入一段HTTP头描述。在本例中,我们只指定了Content-type。

在完成了HTTP头后,我们可以写入HTTP正文。在本例中,我们用一个方法来同时完成写入正文及关闭连接。end方法将会关闭HTTP连接。但因为我们同时还传入了一个字符串,end方法将在把此内容发送给客户端后才关闭连接。

例子的最后一行调用了console.log方法。就像Firebug和Web Inspector 支持的浏览器对应方法那样,它将在标准输stdout上打印信息。

让我们在Node.js终端上运行此程序,并看看运行结果(例1-10)。

例1-10 运行“Hello World”程序

Enki:~ $ node

> var http = require('http');

> http.createServer(function(req, res){

... res.writeHead(200, {'Content-Type': 'text/plain'});

... res.end('Hello World\n');

... }).listen(8124, "127.0.0.1");

> console.log('Server running at http://127.0.0.1:8124/');

Server running at http://127.0.0.1:8124/

node>

在这里我们运行Node解析器,然后输入例子中的代码(我们不介意你从网站上进行复制粘贴)。Node解析器接受了代码,并用“…”提示你的输入未完成并等待补充完整。当我们运行到console.log那行时,Node解析器打印出Server running at http://127.0.0.1:8124/。现在我们可以在浏览器中访问“Hello World”例子了(如图1-1所示)。图1-1:在浏览器中访问“Hello World”

跑起来了!虽然这不是一个惊人的演示,但我们只用了6行代码就把“Hello World”程序运行起来了。我们并不推荐这样的代码风格,但我们已经往前迈出第一步了。在下一章中,我们将看到更多的代码,但接下来我们先思考一下为什么Node会发展成为现在这个样子。1.3 为什么选择Node

在写本书的时候,我们清楚地知道Node.js是多么地新。许多平台要经历多年才被人们接受,而在Node.js这一崭新的平台上,人们却展现了前所未有的热情。我们希望通过探究人们热衷于Node.js的原因,帮助你找到能产生共鸣的特性。通过了解Node.js的强项,我们能发掘出它最擅长的领域。本节将讨论是哪些因素造就了Node.js,它为何能快速流行。1.3.1 高性能Web服务器

当我们在10多年前第一次开始编写Web应用的时候,Web还非常小。当然,期间我们经历了.com泡沫。但那时从事互联网行业的人数还是相当少,创建的网站也没现在这么火热。时至今日,有了先进的Web 2.0和随时随地可以上网的手机,这对我们这些开发人员提出了更多的要求。我们不但要提供更复杂、更多交互、更接近生活的功能,而且有越来越多的用户通过各种设备频繁使用这些功能,这是一个极大的挑战。硬件在持续改进,同时我们也需要提高软件开发水平来支持这些需求。如果只是单纯地采购更多的硬件来支撑新功能和新用户,就不那么划算了。

Node给Web服务器程序开发领域引进了事件驱动编程,来尝试解决这一问题。实践证明,虽然Node不是第一个尝试此方法的平台,但它是目前为止最为成功的平台,而且我们认为它使用起来也是最容易的。后续章节会详细分析事件驱动编程,在这里我们先对其进行简短的介绍。想象一下,你现在需要连接到一台Web服务器上获取一个网页,这在正常的DSL连接速度下通常需要花费100毫秒左右。如果连接的是一台普通的Web服务器,它会在服务器上为你的请求创建一个新的程序运行实例。该程序自顶向下运行(按顺序运行所有的函数)来响应请求并生成网页返回给你。这意味着该服务器在请求被满足前需要一直占用固定大小的内存,其中包括了把数据返回给你所要等待的100多毫秒。Node则不是采用此方式,而是在同一个程序内服务所有的用户。每当Node需要等待一些费时的操作,比如等待确认你已经收到返回的数据时(好让它标记此请求已经完成),它就继续处理下一个用户的请求去了。我们对细节描述得还是太多了,但这些特性意味着Node在内存处理上比传统服务器程序高效得多,也就是能够同时快速地服务更多的用户。这是个巨大的成就,人们也为此而热爱Node。1.3.2 专业的JavaScript

人们喜欢Node的另一个原因是JavaScript。Brendan Eich在 1995年发明了JavaScript语言,这是一门在Netscape浏览器上使用的简单脚本语言。令人惊讶的是自从JavaScript出现以来,它已经不止运用在浏览器上了。早先Netscape服务器程序就支持JavaScript作为一门服务器端脚本语言(称为LiveScript)。虽然JavaScript当时并没有在服务器端得到广泛应用,却毫不妨碍它在快速发展的浏览器市场上大受欢迎。JavaScript和微软的VBScript展开了激烈竞争,都想成为Web上的主流开发语言。很难说明为什么JavaScript最终胜出,也许[2]是因为微软允许JavaScript运行在IE浏览器上 ,也许是因为JavaScript语言本身优势明显,无法不脱颖而出,总之它完胜了。于是,在2000年初期,JavaScript已经成为Web开发语言的代名词,不只是在浏览器开发HTML的第一选择,而且是唯一的选择。

这和Node.js又有什么关系呢?首先我们要记得当AJAX革命发生,并且Web风头正劲的时候(想想 Yahoo!、Amazon、Google 等是多么风光),AJAX中“J”的唯一选择就是JavaScript,完全没有其他替代品。这导致整个行业急需大量优秀的JavaScript程序员。Web成为一个真正意义上的平台,并且附带着JavaScript是其开发语言,这就要求我们这些JavaScript程序员去提升自身能力。JavaScript被视为程序员的第二或第三门编程语言,这本身就反映出人们对其重要性的重新认识。此时涌现出许多专家,他们的努力使JavaScript越来越为人们所接受。

这一运动的带头人物当属Douglas Crockford。他关于 JavaScript的文章和视频很受欢迎,帮助许多程序员发现了这门备受指责的语言中所隐藏的内在美。许多使用JavaScript的程序员为了处理HTML和XML文档,把主要精力花费在了浏览器对W3C DOM API的不同实现上。可悲的是,DOM可能是API中最丑陋的,而且各款浏览器的实现又是那么地不一致和不完整。也难怪过去十年里许多程序员都没有把JavaScript认作一门“严肃”的语言。最近,Douglas关于JavaScript好处(the good parts)的论述让人们认识到这门语言虽有弊病,但仍存在许多宝贵之处,因而带动了此语言的振兴。

在2012年的今天,有越来越多的JavaScript专家倡导JavaScript代码应当精心编写、高性能、易维护。Douglas Crockford、Dion Almaer、Peter Paul Koch(PPK)、John Resig、Alex Russell、Thomas Fuchs 等许多专家对此进行了研究、提议和加工,其中最主要的是提供了程序库,这些程序库让全世界成千上万的专业JavaScript程序员能以追求卓越的精神去从事自己的行业。jQuery、YUI、Dojo、Prototype、Mootools、Sencha等许多程序库部署在各个网站上供大量用户每日使用。在JavaScript不但被接受,还被广泛应用和拥护的环境下,这样的平台也许比Web本身更为宽广。当这么多的程序员了解了JavaScript时,这样的普及就成为了它的一个明显优势。

如果你在一屋子Web程序员中调查他们使用什么语言,会了解到Java和PHP是最流行的,Ruby可能是目前次流行的(或者说至少和Python流行程度相当),Perl则依然有许多追随者。但几乎可以肯定,任何从事Web开发的人都使用过JavaScript。虽然后端语言与浏览器直接割裂开来,但编程这事儿都脱离不了部署这一环节。各种各样的浏览器及浏览器插件允许使用不同的语言,但这些语言都不足以成为Web开发的通用语言。现在我们面前有这样一个单一且通用的Web开发语言,我们怎样才能把它放到服务器上去呢?1.3.3 浏览器之战2.0

在互联网初期,我们就经历了恶名昭著的浏览器之战。Internet Explorer和Netscape在Web功能上竞争激烈,他们分别在各自的浏览器上添加各种不兼容别人的编程特性,而且不支持其他浏览器所具备的功能。对于那些编写Web程序的开发者来说,这些都是苦闷的来源,因为这使得 Web 开发非常烦琐。Internet Explorer或多或少成为了该轮竞争的胜者,变成了主流浏览器。几年之后,当微软在IE6上裹足不前的时候,出现了一个新的竞争者:从Netscape的旧成员中诞生的Firefox。Firefox让浏览器市场风云再起,WebKit(Safari)和Chrome紧跟其后。其中最有趣的还是在浏览器市场中新的竞争情况。

与浏览器之战的第一轮交锋不同,今天的浏览器主要争夺两个战场:一是坚持上一次浏览器战争后出现的标准,二是性能。随着网站越来越复杂,用户都想要最快的体验。这意味着,浏览器不但要很好地支持Web标准和允许开发者进行优化,还要尽力在自己内部进行优化。以JavaScript为核心模块的Web 2.0时代,AJAX 网站已经成为新的战场。

每个浏览器都有各自的JavaScript解析器:Firefox的Spider Monkey、Safari 的Squirrel Fish Extreme、Opera的Karakan,最后还有Chrome带来的V8。这些解析器不断追求更快的性能,也为JavaScript制造了创新的环境。为了让自己的浏览器突围而出,厂商们将尽最大能力让它运行得越来越快。第2章 编写有趣的应用

过去几年,编程变化的趋势是让复杂的应用变得越来越容易开发。我们当然不能错过此等好事,而Node是专注于创建网络应用的,网络应用就需要许多I/O(输入/输出)操作。让我们一起创建几个I/O应用,来看看使用Node有多么简单,并且还能轻松扩展规模。2.1 创建一个聊天服务器

我们生活在一个实时的世界里,有什么比聊天更加实时吗?那就让我们先写一个基于TCP的聊天服务器吧,并且支持Telnet连接。这很容易,而且能够完全用Node来编写。

首先,我们需要在Node中包含TCP模块,并创建一个新的TCP服务器(例2-1)。

例2-1 创建新的TCP服务器

var net = require('net')

var chatServer = net.createServer()

chatServer.on('connection', function(client){

client.write('Hi!\n');

client.write('Bye!\n');

client.end()

})

chatServer.listen(9000)

代码第一行,我们加载了net模块。这个模块包含了Node需要的所有TCP功能。接着,我们调用net.createServer()方法来创建一个新的TCP服务器。有了这个服务器,我们需要用它做点儿事。这里调用on()方法来添加一个事件监听器。每当有新的客户端通过网络连接接入服务器,就会触发connection事件,事件监听器就会调用我们指定的函数。

连接事件在调用回调函数时,会传给我们新客户端所对应的 TCP socket对象的引用。我们把此引用命名为client。调用client.write(),就能发送信息给该客户端。目前,我们只是简单地发送“Hi!”和“Bye!”,然后调用client.end()方法来关闭连接。就这么简单,我们的聊天服务器已经初露端倪了。最后,需要调用listen()函数,好让Node知道监听哪个端口。让我们马上测试一下吧。[3]

我们可以使用Telnet(大多数操作系统都自带此程序)来连接新服务器进行测试。首先,调用node命令并带上文件名来启动服务器。然后,打开Telnet连接到localhost的9000端口(这是我们在Node程序中指定的端口)。见例2-2。

例2-2 用 Telnet连接Node TCP服务器

Console Window 1h

----------------

Enki:~ $ node chat.js

Chat server started

Console Window 2

----------------

Last login: Tue Jun 7 20:35:14 on ttys000

Enki:~ $ telnet 127.0.0.1 9000

Trying 127.0.0.1...

Connected to localhost.

Escape character is '^]'.

Hi!

Bye!

Connection closed by foreign host.

Enki:~ $

到目前为止,我们创建了一个服务器,它能够接受客户端的连接,并且在断开连接前发送了一小段内容。但这还不能称为聊天服务器,我们再来添加几个功能吧。首先,需要能收到客户端发送的消息(例2-3)。

例2-3 监听所有的连接请求

var net = require('net')

var chatServer = net.createServer()

chatServer.on('connection', function(client){

client.write('Hi!\n');

client.on('data', function(data){

console.log(data)

})

})

chatServer.listen(9000)

这里添加了另外一个事件监听器,调用的是client.on()。注意,我们是在connection回调函数的作用域中添加的这个事件监听器,这样就可以访问到连接事件所对应的client对象。新监听器关注的是data事件,每当client发送数据给服务器时,这一事件都会被触发。接着要删掉client.end()这一行。如果关闭了和客户端的连接,又如何获得新的数据呢?(当然,说“再见”那一行同样也删掉了。)现在,无论我们发任何数据给服务器,它都会在终端打印出来。让我们看看例2-4。

例2-4 从Telnet发送数据到服务器

Console 1

-------------

Enki:~ $ node chat.js

Chat server started

Console 2

------------

Enki:~ $ telnet 127.0.0.1 9000

Trying 127.0.0.1...

Connected to localhost.

Escape character is '^]'.

Hi!

Hello, yourself

发生什么事情了?我们运行服务器并用Telnet连上了它。服务器

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载