当前位置: 首页 > 新闻 > 信息荟萃
编号:4746
代码逆袭:超实用的Node.js代码段.pdf
http://www.100md.com 2020年4月17日
第1页
第5页
第20页
第30页
第37页
第535页

    参见附件(44878KB,584页)。

     代码逆袭是周敏写的关于Node.js代码段的书籍,主要讲述了Node.js模块与包管理,Buffer模块处理,Node.js进程管理,OS模块应用以及Node.js Util常用工具等等内容。

    代码逆袭内容

    《超实用的Node.js代码段》精选300余段Node.js代码,涵盖了服务器端脚本开发中的绝大多数要点、技巧与方法,堪称史上最实用的Node.js框架开发方面的参考书籍,是网站建设与服务器端开发人员的好帮手。《超实用的Node.js代码段》的代码跨平台、跨设备、跨浏览器,充分向读者演示了如何使用Node.js框架的各项技术。

    《超实用的Node.js代码段》从Node.js框架的使用原理与应用场景出发,对最实用的Node.js代码段进行了全方位的介绍和演示。《超实用的Node.js代码段》分为15章,包含控制台、模块和包管理、异步I/O与Async流程控制库、Buffer、进程管理、子进程通信、OS操作系统、文件系统、路径处理、TCP/UDP网络编程、流(Stream)、Web开发、常用工具及MySQL与MongoDB数据库交互等Node.js框架技术的内容,对提高网站建设与服务器端开发人员的Node.js技术水平有着非常重要的指导作用。

    《超实用的Node.js代码段》内容简洁明了、代码精练、重点突出、实例丰富、语言通俗易懂、原理清晰明白,是网站建设与服务器端开发人员的良好选择,同时也非常适合大中专院校学生学习阅读。

    书籍作者资料

    周敏,6年互联网、4年Web前端开发经验,从事过产品、前端、后端等职务,技术娴熟,一专多能,如LN(A)MP平台的开发、软件架构、设计模式、HTML 5、JavaScript、CSS等。目前在某著名网站担任全栈工程师,特撰写此书,以帮助更多的初学者学习前、后端的合作开发模式,学习全栈工程师的一些工作技巧。

    Node.js框架概述

    Node.js是一个基于Google公司Chrome浏览器的JavaScript运行时建立的平台,主要用于搭建响应速度快、方便扩展的服务器Web应用。其实,Node本身就是一个JavaScript运行环境,是对GoogleV8引擎的完美封装。GoogleV8引擎执行JavaScript脚本的速度非常快、性能非常好,Node.js框架对它进行了优化,提供了相应替代的API,保证V8引擎在非浏览器环境下运行得更好。

    Node.js框架基于事件驱动、非阻塞I/O模型,因而得以轻量和高效,非常适合在分布式设备终端上运行数据密集型的实时应用。Node.js框架采用一套“非阻塞”I/O库来支持事件循环的方式,更好地为文件系统、数据库之类的资源提供了接口。目前,由于Web服务器与富客户端浏览器应用程序之间共享代码的方法只能通过JavaScript脚本语言来实现,因此对服务器脚本语言支持最完美的Node.js框架发展十分迅猛,实际上已经成为了服务器端的JavaScript脚本语言开发平台。

    更为重要的是,在Node.js框架发布以来的很短时间内,各大开源社区就已经贡献了大量的扩展库(模块),提供了对各种开源软件或数据库驱动的支持。因此,虽然Node项目还非常年轻,但众多的软件开发人员都对Node项目展现出了极大的热情 ......

    内容简介

    本书精选300余段Node.js代码,涵盖了服务器端脚本开发中的绝大多数要点、技巧与方法,堪称史上最实用的Node.js框架开发方面的参考书籍,是网站建设与

    服务器端开发人员的好帮手。本书的代码跨平台、跨设备、跨浏览器,充分向读者

    演示了如何使用Node.js框架的各项技术。

    本书从Node.js框架的使用原理与应用场景出发,对最实用的Node.js代码段进

    行了全方位的介绍和演示。全书分为15章,包含控制台、模块和包管理、异步IO与

    Async流程控制库、Buffer、进程管理、子进程通信、OS操作系统、文件系统、路

    径处理、TCPUDP网络编程、流(Stream)、Web开发、常用工具及MySQL与

    MongoDB数据库交互等Node.js框架技术的内容,对提高网站建设与服务器端开发人

    员的Node.js技术水平有着非常重要的指导作用。

    本书内容简洁明了、代码精练、重点突出、实例丰富、语言通俗易懂、原理清

    晰明白,是网站建设与服务器端开发人员的良好选择,同时也非常适合大中专院校

    学生学习阅读。未经许可,不得以任何方式复制或抄袭本书之部分或全部内容。

    版权所有,侵权必究。

    图书在版编目(CIP)数据

    超实用的Node.js代码段周敏编著.—北京:电子工业出版社,2015.11

    (代码逆袭)

    ISBN 978-7-121-27431-2

    Ⅰ.①超… Ⅱ.①周… Ⅲ.①JAVA语言—程序设计 Ⅳ.①TP312

    中国版本图书馆CIP数据核字(2015)第249419号

    责任编辑:董 英

    印 刷:

    装 订:

    出版发行:电子工业出版社

    北京市海淀区万寿路173信箱

    邮 编:100036开 本:787×1092 116

    印 张:22.75

    字 数:553千字

    版 次:2015年11月第1版

    印 次:2015年11月第1次印刷

    印 数:3000册

    定 价:59.00元

    凡所购买电子工业出版社图书有缺损问题,请向购买书店调换。若书店售缺,请与本社发行部联系,联系及邮购电话:(010)88254888。

    质量投诉请发邮件至zlts@phei.com.cn,盗版侵权举报请发邮件到

    dbqq@phei.com.cn。

    服务热线:(010)88258888。前 言

    近些年Node.js框架作为一种服务器端脚本语言的开发技术,在IT圈内可谓是

    刮起了一股热旋风。因为大家发现,原来仅仅运行于浏览器端的JavaScript脚本也

    可以运行在服务器端,这简直太震撼人心了。于是,学习和掌握Node.js框架开发

    技术成了众多开发设计人员的热切期望。

    本书是一本讲解代码实践的书,它为读者全面深入地讲解了针对各种场景的

    Node.js技术。300余段的代码给读者带来的不仅仅是全面的基础知识,更是为读者

    提供了设计简洁高效的服务器端代码与网站架构、应对跨平台与跨浏览器兼容、优

    化服务器性能等切实问题的解决之道。可以说,本书是学习Node.js框架开发技术

    的高效助手。

    Node.js框架中的那些事儿

    对于大多数刚刚接触Node.js框架的读者,可能一时无从下手,那么Node.js技

    术的难点都有哪些方面呢?

    跨平台与浏览器的兼容

    正确理解服务器端脚本使用

    模块和包管理

    异步IO与Async流程控制库

    进程与子进程通信

    文件与路径处理? Node.js事件处理机制

    TCPUDP网络编程

    HTTPHTTPS应用编程

    Node.js与AJAX应用

    Node.js与数据库交互

    以上所有内容在本书的代码中都有讲解,除了这些常见Node.js技术难点外,本书还力求将最有用的Node.js代码段汇总在一起,提供各种解决实际问题的方

    案。

    Node.js框架学习方法

    11个字就能帮助我们更好地学习Node.js。

    多看、多练:观摩成功的网页设计,分析并练习网页设计中常用的

    代码。

    多想、多问:思考设计实现的原理,提出自己的问题并通过各种渠

    道来寻找答案。

    多总结:记录前人已经探索出来的Node.js技巧,总结实战中碰到

    的问题及解决方案。

    只要真正能做到勤思考、勤动手、勤总结,Node.js学习定能一马平川。

    本书的编写特点

    独特的Node.js切入点

    与市面上其他Node.js相关的书不同,本书从最常见的场景应用角度出发,直接应用Node.js代码段实现功能操作,全部是最实用的例子,全部

    是最透彻的分析!

    内容丰富,知识全面

    本书以Node.js框架各个模块的场景应用作为基础,立体式、全方位地解

    释各种场景下的Node.js代码段应用,场景丰富、实例丰富,并拥有良好

    的可扩展性、可复用性。

    去中心化,分布式学习

    本书的代码实例都是独立的,读者可以从中间开始学,也可以从头开始

    学。代码跨平台、跨设备,可以在平板电脑上学,也可以在PC上学,甚

    至,手机上写代码也是完全可能的。

    Node.js框架原理与实践相结合

    Node.js框架是一个强大的服务端脚本开发库,无论读者具有什么编程背

    景,都可以通过它来优化、改进自己的服务器网站。本书的代码段基于简

    单易学的原理,提供了丰富多样的操作特性,这使得本书成为了适用于各

    类脚本编程的必备工具。

    涵盖内容全面

    本书的实例从控制台应用、模块和包管理、异步IO与Async流程控制库、Buffer、进程管理、子进程通信、OS操作系统、文件系统、路径处理、TCPUDP网络编程、流(Stream)、Web开发、常用工具及数据库交互等方

    面的内容出发,由简入繁、点面结合、配合原理解释,给读者呈现了一场

    代码盛宴。

    自发式学习

    在学习代码前,先让读者练习实际上最基础却最容易做错的Node.js框架

    代码和面试题,激发读者的学习斗志。

    本书的设计始于功能、终于代码,是IT设计人员的案头必备参考书。本书的内容安排

    本书共15章,各章节实现了不同类别的Node代码段。

    第1章 主要介绍了Node.js框架的控制台模块,通过该模块的方法可以向操

    作系统控制台实现各种格式化输入和输出等操作,也就是读者所熟知的“读取-求

    值-输出”循环(Read-Eval-Print Loop,简称REPL)交互式的编程环境。

    第2章 主要介绍了Node.js框架自有的一套模块加载系统,通过该模块可以

    把各个功能拆分、封装到不同的模块之中,在需要的时候调用该模块。Node.js框

    架使用模块和包来组织管理,从性质及加载方式上可以分为以下几类内容:核心模

    块、文件模块、从文件夹加载、文件夹作为模块和模块缓存。

    第3章 主要介绍了Node.js异步IO编程,Node.js框架在设计之初就被考虑

    作为一个高效的Web服务器而存在,因此高效的异步机制贯穿于整个Node.js框架的

    编程模型之中。通过本章的介绍,读者可以学到异步IO机制、异步IO应用和

    Async流程控制库应用等Node.js框架异步编程的内容。

    第4章 主要介绍了Node.js框架中Buffer的概念,它可以理解为是缓冲区或

    临时存储区,是暂时存放输入、输出数据的一小块内存。如果读者学过C语言编程,对指针数组的概念有一定的了解的话,那么学习和掌握Node.js框架的Buffer就会

    容易很多。

    第5章 主要介绍了使用Node.js框架中功能强大的进程管理模块

    (Process)的方法。Process模块是Node.js框架的一个全局内置对象,Node.js

    代码可以在任何位置访问该对象,实际上这个对象就是Node.js代码宿主的操作系

    统进程对象。使用Process模块可以截获进程的异常、退出等事件,可以获取进程

    的环境变量、当前目录、内存占用等信息,还可以进行工作目录切换、进程退出等

    操作。

    第6章 主要介绍了使用Node.js框架的child_process模块创建子进程的四

    个方法,分别是spawn、exec、execFile和fork。其中spawn是最原始的创建子进程的方法,其他三个都是通过对spawn方法不同程度的进一步封装

    实现的。使用child_process模块提供的这些方法,可以实现多进程任务、操作

    shell和进程通信等操作,实用功能是非常强大的。

    第7章 主要介绍了Node.js框架中的操作系统(OS)模块,该模块提供了一

    系列与操作系统相关的函数方法,不过这些方法相对简单,实现的功能也十分有

    限。

    第8章 主要介绍了Node.js框架中的文件系统(File System)模块如何来

    支持IO操作的方法,这些操作方法是对标准POSIX函数的简单封装,它提供了文件

    的读取、写入、更名、删除、遍历目录、链接等POSIX文件系统操作。

    第9章 主要介绍了Node.js框架中的路径处理(Path)模块、url路径处理

    (url)模块以及字符串解析(Query String)模块,这些模块提供了一系列与

    路径解析处理相关的函数方法,这些方法对于处理常规的需求是足够的。

    第10章 主要介绍了Node.js框架中对TCPUDP网络编程方面的支持,Node.js框架为设计人员提供了网络(Net)模块来支持TCP协议应用,数据报套接

    字(UDP)模块来支持UDP协议应用,这两个模块提供了一系列与网络应用相关的函

    数方法,通过这些方法可以构建基本的网络应用。

    第11章 主要介绍了Node.js框架中的抽象接口流(Stream)模块,流

    (Stream)模块操作最主要的是.pipe方法,它可以为开发者提供可以重复使用

    的统一的接口,通过抽象的流(Stream)接口来控制流(Stream)之间的读写平

    衡。

    第12章 主要介绍了应用Node.js框架中的HTTP模块与HTTPS模块开发Web应

    用的方法,这两个模块基于HTTP协议与HTTPS协议开发,提供了一系列与Web应用开

    发相关的函数方法,通过这些方法可以构建各种功能复杂且强大的Web应用。

    第13章 主要介绍了Node.js框架中的常用工具(Util)模块,该模块是为了

    解决核心JavaScript的功能过于精简而设计的。该模块可以实现对一个原型对象的

    继承功能,实现对象格式化操作、将任意对象转换为字符串操作、调试输出功能、正则表达式验证等。

    第14章 主要介绍了Node.js框架与MySQL数据库交互的方法,主要选用的是

    目前人气最高的node-mysql开源项目作为Node.js框架MySQL扩展库,该开源项目

    提供了MySQL数据库对Node.js框架的完整支持,具有一套与数据库开发相关的函数

    方法,通过这些方法就可以非常方便地构建Node.js数据库应用。

    第15章 主要介绍了Node.js框架与MongoDB数据库交互的方法,主要选用的

    是同名的mongodb开源项目作为Node.js框架的MongoDB扩展库,该扩展库具有一套

    与数据库开发相关的函数方法,通过这些方法就可以非常方便地构建Node.js数据

    库应用。

    本书面对的读者

    Web服务器设计入门者

    Web服务器开发入门者

    Node.js框架学习爱好者

    由JavaScript向Node.js框架转型的开发人员

    中小型企业网站开发者

    大中专院校的学生

    各种IT培训学校的学生

    网站后台开发人员

    网站建设与网页设计的相关威客兼职人员

    本书的服务笔者能力有限,如果读者发现我们在写作过程中有什么疏漏,或者您对本书有

    什么疑问,可通过以下方式与我们沟通。

    QQ群:296811675,作者在线答疑。

    扫描封底的微信二维码,时刻参与我们的图书互动。

    通过新浪微博@博文视点Broadview,了解我们发布的信息和各种

    前端流行技术。

    博文视点官方网站http:www.broadview.com.cn,下载本书

    所有实例源代码。

    Github,https:github.comkingwjzNode.js-code,了解

    代码的实时更新和迭代过程,可以在每章代码下参与讨论,也可以观看其

    他读者提出的问题,还可以随时随地下载代码。

    很多读者在学习过程中苦于无法交流,小故障无法及时解决,加入我们的服务

    方阵,我们将为您提供终生免费的服务。一本书、一段情、一辈子。

    本书的思维导图编者推荐

    本书摒弃传统的说教模式,每段代码都是单独的功能型页面,读者可以从全书

    的任意一点开始线性阅读。本书的目的就是将最有用的代码与读者分享,包含了服

    务器设计人员在实战中必须具备的所有技巧和方法,读者可以拿来就用。本书300余

    段代码也许并不是最优的代码,但笔者提供了Github地址,与全世界IT工程师一起

    优化了这些代码,并实现了更新迭代,以保证读者始终能看到最好的、最高效的、最实用的Node代码段。这是一本市场上绝无仅有的Node实战书,是一本值得拥有的

    Node设计书。序1 Node.js的前世今生

    的热情,并贡献出了自己的一份力量,改进并完善了Node.js框架。

    此,虽然Node项目还非常年轻,但众多的软件开发人员都对Node项目展现出了极大

    贡献了大量的扩展库(模块),提供了对各种开源软件或数据库驱动的支持。因

    更为重要的是,在Node.js框架发布以来的很短时间内,各大开源社区就已经

    展十分迅猛,实际上已经成为了服务器端的JavaScript脚本语言开发平台。

    JavaScript脚本语言来实现,因此对服务器脚本语言支持最完美的Node.js框架发

    口。目前,由于Web服务器与富客户端浏览器应用程序之间共享代码的方法只能通过

    塞”IO库来支持事件循环的方式,更好地为文件系统、数据库之类的资源提供了接

    在分布式设备终端上运行数据密集型的实时应用。Node.js框架采用一套“非阻

    Node.js框架基于事件驱动、非阻塞IO模型,因而得以轻量和高效,非常适合

    了相应替代的API,保证V8引擎在非浏览器环境下运行得更好。

    JavaScript脚本的速度非常快、性能非常好,Node.js框架对它进行了优化,提供

    一个JavaScript运行环境,是对Google V8引擎的完美封装。Google V8引擎执行

    台,主要用于搭建响应速度快、方便扩展的服务器Web应用。其实,Node本身就是

    Node.js是一个基于Google公司Chrome浏览器的JavaScript运行时建立的平

    Node.js框架概述

    师益友,拥有这些代码,你将会在服务器脚本工作中战无不胜!

    能的优化、快速开发服务器的应用。所以本书不仅仅是你的帮助文档,更是你的良

    这是一本是有显著特点的Node.js书,它涉及了脚本编程的技巧、脚本运行性Node.js框架环境搭建

    学习Node.js框架的第一步,需要先搭建好其工作环境,这样才能运行并测试

    Node脚本文件。下面具体介绍一下。

    (1)获取Node安装包,可以访问以下Node.js框架官方网址:

    https:nodejs.orgdownload

    在该页面中,可以看到适用于不同操作系统的、各个版本的Node安装包源文

    件,选中我们需要的版本类型直接下载就可以。

    在Windows操作系统环境下安装Node.js框架,直接运行下载好的Node安装包

    源文件即可,目的路径一般选择如下:

    D:nodejs

    安装完毕后,读者可以到该目录下浏览一下具体内容,这样会对Node环境有一

    个大致的了解。

    (2)在Ubuntu(Linux)环境下需要运行apt命令进行安装,具体方法如下:

    sudo apt-get install nodejs

    如果想获取最新的Node安装源,具体方法如下:

    sudo add-apt-repository ppa:chris-leanode.js

    sudo apt-get update

    sudo apt-get install nodejs

    一般情况下,node命令会被自动安装在以下路径之中(视不同的Ubuntu系统版

    本而定):

    usrlocalbinnode

    IDE这款插件来开发Node程序。读者可以从下面的网址获取该插件工具:

    对于已经习惯了使用Eclipse开发工具的读者来讲,可以使用EclipseNode.js (3)Eclipse Node.js IDE插件

    http:www.sublimetext.com

    操作系统。读者可以从下面的网址获取该工具:

    Sublime Text也是一款跨平台的编辑器,完全支持Windows、Linux、Mac OS X等

    的扩展功能,比如支持代码缩略图、各种工具插件、多窗口任务等功能。同时,等),同时也可以作为文本编辑器使用。Sublime Text具有漂亮的用户界面和强大

    Sublime Text是一款代码编辑器(支持C、Java、JavaScript、HTML、CSS

    (2)Sublime Text代码编辑器

    http:www.jetbrains.comwebstorm

    操作系统,有“Web前端开发神器”的美誉。读者可以从下面的网址获取该工具:

    JavaScript开发者作为首选的开发平台,完全支持Windows、Linux、Mac OS X等

    WebStorm是jetBrains公司开发的一款JavaScript开发工具,被众多

    (1)jetBrains公司的WebStorm开发工具

    1.开发工具,平台类

    Node.js框架推荐工具

    如果显示出正确的版本号,则说明Node环境搭建成功了。

    node –v

    是否正确,可以使用以下命令来检测Node的版本:

    大致经过以上这几步的操作,Node.js框架就安装完毕了,为了检验Node环境http:www.nodeclipse.org

    (4)Node.js Tools for Visual Studio插件

    如果读者习惯使用微软公司的Visual Studio系列开发工具,同样有一款

    Node.js Tools for Visual Studio插件可以提供对开发Node程序的支持。读者

    可以从下面的网址获取该插件工具:

    https:nodejstools.codeplex.com

    2.测试调试工具类

    (1)NodeUnit

    NodeUnit是一款应用于Node.js的单元测试框架,基于assert模块开发,读者

    可以从下面的网址获取该测试工具:

    https:github.comcaolannodeunit

    (2)Supervisor

    如果希望在Node代码修改后立即看到效果,而不是每次都要重启Node服务才能

    看到效果,Supervisor调试工具可以帮助实现这个功能,它会监视代码的改动并自

    动重启Node服务。读者可以从下面的网址获取该测试工具:

    http:supervisord.org

    (3)Mocha

    Mocha是一款完整的测试工具,可安装在NPM和CI服务器之上。读者可以从下面

    的网址获取该测试工具:

    https:github.commochajsmocha

    (4)should.jsshould.js模块是assert模块的扩展,其语法与日常用的语法几乎一模一样,非常易于使用。读者可以从下面的网址获取该测试工具:

    https:github.comvisionmediashould.js

    3.第三方开发包类

    (1)Async异步处理

    Async是一个流程控制工具包,提供了直接而强大的异步功能,该插件基于

    JavaScript语言专门为Node.js设计,同时也可以直接在浏览器中使用。读者可以

    从下面的网址获取该开发工具:

    https:github.comcaolanasync

    (2)Express开发包

    Express是一个简洁而灵活的Node.js Web应用框架,提供一系列强大特性,帮助我们创建各种Web应用。Express不对Node.js已有的特性进行二次抽象,只是

    在其之上扩展了Web应用所需的功能。Express开发包所具有的丰富的HTTP工具以及

    来自Connect框架的中间件可以为审计人员随取随用,并创建出友好的、快速且简

    单的API。读者可以从下面的网址获取该开发工具:

    https:www.npmjs.compackageexpress

    (3)node-mysql开发包

    node-mysq开发包是一个纯Node.js的用JavaScript实现的MySQL客户端程

    序。node-mysql封装了Node.js框架对MySQL的基本操作,拥有100%的MIT公共许

    可证。读者可以从下面的网址获取该开发工具:

    https:github.comfelixgenode-mysql

    本书浏览器约定本书涉及的浏览器测试基准如图1所示,可以看到内核和外壳的占有情况,内环

    为内核,外环为外壳,这也是接下来要提到的浏览器同类项的数据基础。

    广,因此基准中只保留其最新版本。

    较大,因此IE需要测试6~10的所有版本,然而由于Firefox和Chrome升级覆盖面

    试,开发者要了解内核对标准的支持,比如IE的渲染引擎Trident的不同版本差别

    浏览器的不同版本的内核也不一样,因此通常要针对不同版本的浏览器做测

    测试基准中的浏览器应当具有典型代表性。

    试基准除了要基本反映浏览器的市场占有率,还要考虑到开发测试的成本。因此,内核或对W3C标准有类似的支持程度对浏览器进行归类的。之所以这样做,是因为测

    过其中一个,那么其他与之同类的浏览器也基本上可以通过测试。图1是根据相同的

    方面,某些浏览器具有相同的血统,是可以归为同一类的,同一类中,如果测试通

    性会影响整个网站功能,这也是为什么内核无法完全代表所有浏览器的原因。另一

    不同的浏览器可能会采用相同的内核(渲染引擎)。一方面,外壳实现的差异

    图1 浏览器基准本书涉及的代码会根据需要,对不同浏览器进行有针对性的测试。序2 最简单却必须看的Node代码

    Node代码基于JavaScript代码,却也有所不同,相信通过对本书的学习,读者

    会对Node技术爱不释手!下面介绍一些很简单、却又很有特点的Node代码。

    1.控制台运行Node代码的方法:

    01 node

    02 > console.log('Hello Node!');

    03 Hello Node!

    第01行代码运行Node环境;第02行代码调用Node.js框架的打印输出命令;第

    03行代码为控制台打印输出的结果。

    2.控制台运行Node脚本的方法:

    01 node hello.js

    02 Hello Node!

    第01行代码使用Node命令运行hello.js脚本文件(脚本文件中代码同第1个例

    子中的第02行代码);第02行代码为控制台打印输出的结果。

    3.使用require命令加载模块的方法:

    01 var http = require('http'); TODO: 加载核心模块 ‘http’

    02 var circle = require('.ch02.module-file-circle.js');

    第01行代码使用require命令加载核心模块‘http’;第02行代码使用

    require命令加载自定义模块'.ch02.module-file-circle.js'。

    4.使用exports命令输出对象的方法:01 exports.area = function(r) {

    02 return PI r r;

    03 };

    这段代码使用exports命令输出一个area方法,用于计算圆的面积。

    5.使用async流程库的方法:

    01 async.series([

    02 function(callback) {

    03 callback(null, 'hello');

    04 },05 function(callback) {

    06 callback(null, 'async');

    07 },08 function(callback) {

    09 callback(null, 'series');

    10 }

    11 ],function(err, results) {

    12 console.log(results);

    13 });

    这段代码使用了async流程库的series方法来控制流程,async流程库还有其他

    几种控制方法,读者可以阅读本书的详细内容。

    6. IO异常捕获的方法:

    01 try{

    02 setTimeout(function{

    03 var data = a0; TODO: 错误的计算

    04 },1000);

    05 }catch (e){

    06 console.log(e);

    07 }这段代码演示了使用trycatch语法进行IO异常捕获的方法,第03行代码输出

    了一个错误的计算,第06行代码输出捕获的错误异常。

    7.初始化Buffer对象的方法:

    01 var buffer = new Buffer(This is Buffer, utf8); TODO: 初始化Buffer

    这段代码演示了初始化Buffer对象的方法,并定义了“utf8”编码格式。

    8.获取进程信息的方法:

    01 console.info('当前进程id:');

    02 console.info(process.pid);

    03 console.info('当前进程名称:');

    04 console.info(process.title);

    这段代码演示了通过process模块获取进程id和进程名称的方法。

    9.创建子进程的方法:

    01 var spawn = require('child_process').spawn; TODO: 引入child_process模块

    02 var ls_var = spawn('ls', ['-lh', 'var']); TODO: 定义命令行‘ls -lh var’

    这段代码演示了通过child_process模块创建子进程的方法,并实现了查

    看var目录的命令。

    10.获取操作系统信息的方法:

    01 var type = os.type;

    02 console.info('当前操作系统类型为: ' + type);

    03 var platform = os.platform;

    04 console.info('当前操作系统平台为: ' + platform);

    这段代码演示了通过操作系统OS模块获取操作系统类型和平台信息的方法。

    11.读文件的方法:01 if(fs.existsSync(file_path)) {

    02 var file_contents = fs.readFileSync(file_path, 'utf-8'); TODO: 读文件(同步方式)

    03 console.info('read txtreadFileSync.txt contents: ');

    04 console.info(file_contents); TODO: 打印输出文件内容

    05 console.info;

    06 }

    这段代码演示了通过文件系统fs模块读文件的方法。

    12.规范化字符串路径的方法:

    01 var path = require('path'); TODO: 引入路径处理模块

    02 var path_a = homeking;

    03 console.info('path.normalize(homeking) is : ' + path.normalize(path_a));

    这段代码演示了通过路径path模块规范化字符串路径的方法。

    13.创建TCP服务器的方法:

    01 var net = require('net'); TODO: 引入网络(Net)模块

    02 var HOST = '127.0.0.1'; TODO: 定义服务器地址

    03 var PORT = 9696; TODO: 定义端口号

    04 net.createServer(function(sock) {

    05

    06 添加事件处理方法

    07

    08 }).listen(PORT, HOST);

    这段代码演示了通过网络net模块创建TCP服务器的方法。

    14.创建HTTP服务器的方法:

    01 var http = require('http'); TODO: 引入http模块

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

    03 04 通过res.writeHeader函数方法写HTTP文件头

    05

    06 res.writeHead(200, {'Content-type' : 'texthtml'});

    07

    08 通过res.write函数方法写页面内容

    09

    10 res.write('

Node.js --- HTTP

');

    11

    12 通过res.end函数方法发送响应状态码,并通知服务器消息完成

    13

    14 res.end('

Create Basic HTTP Server!

');

    15 }).listen(6868); TODO: 监听6868端口号

    这段代码演示了通过HTTP模块创建Web服务器的方法。

    15. Node.js框架连接MySQL数据库的方法:

    01 var http = require(http); TODO: 引入HTTP模块

    02 var mysql = require('usrlocallibnode_modulesmysql'); TODO: 引入mysql模块

    03 var connection = mysql.createConnection({

    04 host: localhost, TODO: 主机地址

    05 user: root, TODO: 数据库用户名

    06 password: root, TODO: 数据库密码

    07 database: nodejs, TODO: 数据库名称

    08 port: 3306 TODO: 端口号

    09 });

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

    11 res.writeHead(200, { Content-Type : texthtml;charset=utf8 });

    12 res.write(

测试Node.js - MySQL数据库连接!



    );

    13 connection.connect(function(err) {

    14 if(err) {

    15 res.end('

Error Connected to MySQL!

');

    16 return;17 } else {

    18 res.end('

Connected to MySQL!

');

    19 }

    20 });

    21 }).listen(6868); TODO: 监听6868端口号

    这段代码演示了Node.js框架连接MySQL数据库的方法。序3 Node.js最流行的面试题

    面试题一般不是多么高精尖的问题,在世界500强和中国100强的科技公司中,绝大多数的考题都是基础技术类知识,原因是他们招聘的不是经理,而是具体干活

    的,所以要考查的就是基本功。面试题不一定有统一的标准答案,读者可以自己测

    试。

    1.请简要描述一下Node.js框架的概念。

    【参考答案】Node.js是一个基于Chrome JavaScript运行时建立的平台,用

    于方便地搭建响应速度快、易于扩展的网络应用。Node.js框架使用事件驱动、非

    阻塞IO模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应

    用。Node实际上是一个JavaScript运行环境,对Google V8引擎进行了封装,因为

    V8引擎执行JavaScript的速度非常快,性能非常好。

    2.请简要说明几个Node.js框架的优点。

    【参考答案】

    RESTful API:支持Web服务和动态Web应用程序的多层架构,实

    现可重用性、简单性、可扩展性和组件可响应性的清晰分离。开发人员可

    以轻松使用Ajax和RESTful Web服务一起创建丰富的界面。

    单线程:Node.js单线程是指Node并没有创建一个线程的能力,所

    有代码都是单线程执行的。不过Node宿主环境并不是单线程的,它会维护

    一个执行队列,循环检测并调度JavaScript线程来执行,因此单线程执行

    和并发操作并不冲突。

    事件轮询机制:Node.js可以在不新增额外线程的情况下,依然可以对任务进行并行处理,它是通过事件轮询(event loop)来实现并行操

    作的。

    非阻塞IO:由于Node.js是事件驱动的,因此其使用了事件循环

    来解决IO操作带来的瓶颈问题。在Node.js中,一个IO操作通常会带有

    一个回调函数,当IO操作完成并返回时,就会调用这个回调函数,而主线

    程则继续执行接下来的代码。

    V8虚拟机:Node.js是一个基于Google Chrome V8 JavaScript

    引擎之上的平台,可用以创建轻量级、快速、可扩展、事件驱动和非阻塞

    IO的应用。

    事件驱动:Node.js框架使用事件驱动模型,即当Web Server接

    收到请求时,就将其关闭然后进行处理,然后去服务下一个Web请求。当这

    个请求完成后,它被放回处理队列中,当到达队列开头时,这个结果被返

    回给客户端。

    3.简述Node.js框架适用的应用场景。

    【参考答案】

    (1)面向服务的架构

    面向服务的架构就是做好前、后端的依赖分离,将所有的关键业务逻辑都封装

    成REST调用,上层只需要考虑如何用这些REST接口来构建具体的应用。这样,后台

    程序员们不需要知道具体数据是如何从一个页面传递到另一个页面的,也不需要知

    道用户数据更新是通过Ajax异步获取的还是通过刷新页面获取的。Node.js正适合

    这样的开发场景。

    (2)RESTful API

    前面,我们讲到了RESTful API是Node.js框架的主要优点,因此也是其最理

    想的应用场景。应用RESTful API场景可以处理数万条连接请求,该操作没有太复杂的逻辑,仅仅就是请求API,将数据进行返回即可。简而言之,其本质就是从数据

    库中查找一些值并将其组成一个响应,由于这类响应是很小的文本,同时连接请求

    也是很小的文本,因此整体流量不高,一台服务器往往也可以处理很繁忙的连接请

    求。

    (3)Ajax请求应用

    目前,个性化Web应用十分流行,大数据时代针对个人用户页面的定制信息已经

    成为主流,当缓存失效后需要在页面加载时发起Ajax请求,此时应用Node.js框架

    可以响应大量的并发请求。因此Node.js框架适合运用在高并发、IO密集、少量业

    务逻辑情况下的Ajax请求应用场景。

    4.简述Node.js框架不适用的应用场景。

    【参考答案】

    当然,Node.js框架也不是万能皆适的,有些应用场景也不是它的强项。下面

    可以列举几种供读者参考。

    (1)实时性要求很高的场景,例如工程交换机、工控机器人和DCS集控系统

    等。这些场景基本通过垃圾回收机制来管理系统内存,因此Node.js框架将会影响

    响应速度,并且很难进行优化。

    (2)计算密集型系统,这些应用基本都是C语言的天下,基于JavaScript语言

    的Node.js框架在计算性能上是很难与C语言代码相比的。

    (3)需要单一进程控制大内存的场景,由于Google V8引擎的设计限制,在

    32-bit下有1GB最大内存尺寸的限制,在64-bit下是1.7GB。虽然Node.js框架的

    Buffer分配可以不超过此限制,但是也会带来垃圾回收机制上性能的退化。

    5.谈谈Node异步机制的种类。

    【参考答案】异步机制方法大致包括回调函数、pubsub模式(事件模式)、异步库控制库(async、when等)、promise项目、Generator项目等。6.简述exports与module.exports的区别。

    【参考答案】需要明确的是,module.exports才是真正的接口,而exports只

    不过是module.exports的一个辅助工具,exports是基于module.exports而实现

    的。实际上,全部由exports获取的属性和方法,最后都赋给了module.exports接

    口,不过有个前提就是module.exports本身不具备任何属性和方法。换言之,如果

    module.exports接口已经具备一些属性和方法,那么exports获取的属性和方法将

    被忽略。目 录

    前 言

    序1 Node.js的前世今生

    序2 最简单却必须看的Node代码

    序3 Node.js最流行的面试题

    第1章 Node.js控制台模块应用

    1.1 Node.js版之“Hello World”程序

    1.2 日志输出与信息输出功能

    1.3 字符串格式化的应用

    1.4 数值型格式化的应用

    1.5 JSON数据交换格式应用

    1.6 测试特殊运算符如何取值

    1.7 特殊格式化参数应用

    1.8 斐波那契(Fibonacci)数列应用

    1.9 错误与警告提示应用

    1.10 重定向标准错误输出流

    1.11 查看Node.js对象的属性和方法1.12 时间计时器应用

    1.13 查看当前调用栈的方法

    1.14 对表达式结果进行评估

    1.15 读取命令行输入信息

    1.16 阶乘运算输出

    1.17 向控制台输出组合控制键

    1.18 模拟一个简单的控制台界面

    1.19 输出水仙花数

    1.20 输出质数

    1.21 打印输出杨辉三角

    1.22 汉诺塔(Hanoi)问题

    1.23 简单四则运算应用

    第2章 Node.js模块与包管理

    2.1 Node.js框架加载核心模块

    2.2 Node.js框架加载文件模块

    2.3 从node_modules文件夹中加载

    2.4 模块的循环调用问题

    2.5 module.exports对象应用

    2.6 module.exports对象与exports对象2.7 汇率换算实用程序

    2.8 简单计数器实用程序

    2.9 包管理之package.json详解

    2.10 基于包管理的四则运算应用

    第3章 Node.js异步IO与Async流程控制库

    3.1 Node.js框架异步机制基础

    3.2 Node.js框架异常捕获机制

    3.3 Async串行流程控制

    3.4 Async瀑布模式流程控制

    3.5 Async并行流程控制

    3.6 Async限制性并行流程控制

    3.7 Async循环流程控制

    3.8 Async队列流程控制

    第4章 Buffer模块处理

    4.1 定义Buffer对象的基本方法

    4.2 定义Buffer对象的特别方法

    4.3 如何判断Buffer对象

    4.4 获取Buffer对象字节长度

    4.5 读取Buffer对象4.6 写入Buffer对象

    4.7 Buffer对象转字符串

    4.8 Buffer对象裁剪

    4.9 拷贝Buffer对象

    4.10 正确拼接Buffer

    4.11 应用Buffer操作HTTP Request Header

    第5章 Node.js进程管理

    5.1 获取应用程序当前目录

    5.2 改变应用程序目录

    5.3 获取系统相关信息

    5.4 实现标准输出流

    5.5 实现标准错误流

    5.6 实现标准输入流

    5.7 Kill当前进程

    5.8 Process模块的异步方法

    第6章 child_process及进程通信

    6.1 使用spawn方法创建子进程

    6.2 使用exec方法创建子进程

    6.3 使用spawn方法绑定系统事件6.4 使用exec方法绑定错误事件

    6.5 创建子进程查看用户目录

    6.6 查看用户目录出现错误的处理方法

    6.7 查看物理内存使用状态

    6.8 查看子进程pid的方法

    6.9 创建子进程统计系统登录次数

    6.10 使用execFile方法创建子进程

    6.11 使用execFile方法绑定错误事件

    6.12 使用fork方法获取CPU信息

    6.13 使用fork方法实现进程间通信

    6.14 使用fork方法实现斐波那契数列

    第7章 OS模块应用

    7.1 获取当前操作系统类型与平台

    7.2 获取操作系统默认的临时文件目录

    7.3 获取操作系统主机名

    7.4 获取操作系统架构

    7.5 获取操作系统的发行版本

    7.6 返回操作系统运行时间

    7.7 获取操作系统内存状态7.8 获取CPU内核信息

    7.9 获取网络接口信息

    第8章 文件系统模块应用

    8.1 重命名文件

    8.2 打开与关闭文件

    8.3 截取文件内容

    8.4 修改文件长度

    8.5 获取文件信息

    8.6 更改文件所有权

    8.7 更改文件权限

    8.8 创建与删除文件硬链接

    8.9 创建文件符号链接

    8.10 读取文件符号链接

    8.11 相对路径转绝对路径

    8.12 创建与删除目录

    8.13 读取文件目录

    8.14 读文件的应用

    8.15 功能增强的读文件应用

    8.16 写文件的应用8.17 功能增强的写文件应用

    8.18 追加写入文件

    8.19 监控文件的应用

    第9章 路径处理应用

    9.1 规范化字符串路径

    9.2 合并字符串路径

    9.3 解析绝对路径

    9.4 解析相对路径

    9.5 获取文件夹路径

    9.6 获取路径中文件扩展名

    9.7 如何获取路径中最后部分

    9.8 解析与格式化url路径

    9.9 url路径转化

    9.10 url参数转化url对象

    第10章 TCPUDP网络应用

    10.1 创建基本的TCP服务器

    10.2 创建基本的TCP客户端

    10.3 创建简单的TCP通信应用

    10.4 创建TCP服务器的另一种方式10.5 服务器端绑定事件

    10.6 获取服务器地址参数

    10.7 获取当前服务器连接数

    10.8 获取套接字地址

    10.9 获取远程地址

    10.10 使用套接字写数据

    10.11 控制套接字数据流的应用

    10.12 创建UDP服务器

    10.13 创建UDP客户端

    10.14 创建简单的UDP应用

    10.15 UDP广播服务的实现

    10.16 模仿简单的聊天室应用

    第11章 Node.js流(Stream)应用

    11.1 创建可读(Readable)流

    11.2 测试可读readable事件处理

    11.3 使用data事件读取文件

    11.4 可读流错误事件处理

    11.5 暂停与恢复可读(Readable)流

    11.6 使用可读(Readable)流发送数据11.7 使用可读(Readable)流读取文件

    11.8 使用pipe方法实现复制文件

    11.9 解除pipe方法设置的流

    11.10 使用可写(Writable)流写文件

    11.11 可写(Writable)流drain事件处理

    11.12 可写(Writable)流finish事件处理

    第12章 Node.js Web开发

    12.1 构建一个基本的HTTP服务器

    12.2 编写一个简单的HTTP客户端

    12.3 HTTP响应状态码

    12.4 设定和获取HTTP头文件

    12.5 写HTTP头文件的方法

    12.6 发送与处理GET请求

    12.7 进行重定向操作

    12.8 服务器多路径处理方式

    12.9 模拟ping命令连接服务器

    12.10 安装Express开发框架

    12.11 使用Express开发框架开发的Hello World

    12.12 Express开发框架路由处理12.13 应用Express框架实现登录页面

    12.14 Express框架实现Ajax方式操作

    第13章 Node.js Util常用工具

    13.1 原型对象继承

    13.2 将任意对象转换为字符串

    13.3 验证是否为数组

    13.4 验证是否为日期格式

    13.5 验证是否为正则表达式

    13.6 验证是否为错误类型

    13.7 格式化字符串

    第14章 Node.js与MySQL交互

    14.1 连接MySQL数据库

    14.2 查询MySQL数据库

    14.3 插入MySQL数据库

    14.4 删除MySQL数据库

    14.5 更新MySQL数据库

    14.6 操作MySQL数据库连接池

    第15章 Node.js与MongoDB交互

    15.1 连接MongoDB数据库15.2 连接MongoDB数据集合

    15.3 查询MongoDB数据集合

    15.4 插入MongoDB数据集合

    15.5 删除MongoDB数据集合

    15.6 更新MongoDB数据集合第1章 Node.js控制台模块应用

    Node.js是一个基于Google V8 JavaScript引擎建立的服务器端平台,可以

    用来方便地搭建快速的、易于扩展的Web应用。众所周知,V8引擎执行JavaScript

    的速度非常快,性能非常好。Node.js采用了一个称为“事件循环(event

    loop)”的架构,使得编写可扩展性高的服务器变得既容易又安全。其中,Node.js提供了控制台模块,通过该模块的方法可以向操作系统控制台实现输入和

    输出等操作(比如console.log、console.error等方法),实际上也就是目前非

    常流行的“读取-求值-输出”循环(Read-Eval-Print Loop,简称REPL)交互式

    的编程环境。

    本章主要包括以下内容。

    控制台下console模块各种方法的应用。

    数据的各种格式化输出。

    Node.js框架的跨平台应用。

    Node.js框架下解决几个知名的数学算法问题。

    1.1 Node.js版之“Hello

    World”程序

    我们还是以一个“Hello World”程序开始第一个示例,通过这个例程将

    Node.js平台的几种主要开发环境简要介绍给读者。目前,Node.js平台开发在Windows环境与Ubuntu环境下均十分流行,本书尽可能将两种操作系统环境下的开

    发细节呈现给读者,以帮助读者全方位地了解Node.js平台的强大之处。

    Node.js平台环境的安装这里就不赘述了,刚刚起步的读者可以参考Node.js官

    方网站或者互联网上相关的资源。

    下面就让我们进入主题,看看基于Node.js的“Hello World”具体是什么样

    子的。

    本例ch01.hello-world.js主要代码如下:

    01

    02 ch01.hello-world.js

    03

    04 console.log(Hello World!); 输出日志内容

    1.Windows环境下

    读者可以使用文本编辑器(如EditPlus、NotePad++、UltraEdit等)将以上

    代码保存为ch01.hello-world.js脚本文件来直接使用。Node.js平台强大之处就

    是可以将js脚本程序直接以控制台方式运行,具体执行方式有以下几种。

    (1)控制台终端直接执行js脚本文件,如图1.1所示。

    图1.1 Node.js在控制台终端直接执行js脚本文件

    从图中可以看到,使用node命令直接执行ch01.hello-world.js脚本文件,会在控制台输出运行结果。

    (2)控制台终端以参数方式直接运行,如图1.2所示。

    图1.2 Node.js在控制台终端以参数方式执行js脚本语言

    从图中可以看到,使用node命令带-e参数直接执行脚本语言,并在控制台输出

    运行结果。读者可以在终端使用node -help命令查看关于-e参数的说明,其含义是

    eval script,也就是执行脚本语言的意思。其实,了解JavaScript语言eval

    函数的读者对此并不陌生,两者的功能是基本一致的,就是计算字符串并执行其中

    的JavaScript代码。

    (3)REPL (Read-eval-print loop)方式,如图1.3所示。

    图1.3 Node.js在控制台终端以REPL方式执行js脚本语言

    从图中可以看到,使用node命令进入Node.js平台的shell界面(具有“>”提

    示符的状态),这就是REPL方式。REPL(Read-Eval-Print Loop,简称REPL)表

    示“输入-求值-输出”循环的含义,如果读者输入了一个函数并回车,那么REPL方

    式会直接在下面输出这个函数的执行结果与返回值,本例中的“undefined”就是console.log函数的返回值。但如果读者输入了一个错误的指令,REPL则会立即

    显示错误并输出调用栈。

    2.Ubuntu环境下

    读者可以使用系统自带的文本编辑器(如vi、gedit、sublime-text等)将以

    上代码保存为ch01.hello-world.js脚本文件来直接使用。在Ubuntu环境下执行

    Node.js控制台的方法与在Windows环境下基本类似,以下是几种具体的实现过程。

    (1)控制台终端直接执行js脚本文件,如图1.4所示。

    图1.4 Node.js在控制台终端直接执行js脚本文件

    从图中可以看到,在Ubuntu环境下需要先进入js脚本文件所在的目录,然后再

    使用node命令直接执行ch01.hello-world.js脚本文件,运行结果会在控制台进行

    输出。

    (2)控制台终端以参数方式直接运行,如图1.5所示。

    图1.5 Node.js在控制台终端以参数方式执行js脚本语言

    从图中可以看到,在Ubuntu环境下Node.js在控制台终端以参数方式执行js脚

    本语言的方法与Windows环境下是一致的。(3)REPL (Read-eval-print loop)方式,如图1.6所示。

    图1.6 Node.js在控制台终端以REPL方式执行js脚本语言

    从图中可以看到,在Ubuntu环境下Node.js在控制台终端以REPL方式执行js脚

    本语言的方法与Windows环境下是一致的。

    说明:因为这是本书第一个例程,我们着重介绍了Node.js平台下几种控制台

    运行js脚本语言的方法。在后面例程中我们会选择其中一种方法来运行js脚本语

    言,并将陆续使用几款支持Node.js平台的集成开发软件来运行js脚本语言。

    提示:在Windows环境下与Ubuntu环境下搭建Node.js开发平台的方法略有不

    同,Ubuntu环境下需要编译源程序包后再执行安装,且对Ubuntu文件系统的权限相

    对也有限制,而在Windows环境下安装则相对简单得多,刚刚起步的读者如果遇到

    问题可以发邮件联系我们进行咨询。

    1.2 日志输出与信息输出功能

    既然Node.js平台能够支持控制台操作,那么常规的日志输出与信息输出应该

    也是必有的功能。在下面这一例程中,我们将演示console.log与

    console.info这两个方法具体的应用。

    本例ch01.hello-world.js主要代码如下:

    01

    02 ch01.log-info.js03

    04 console.log(Node.js - console.log 方法); 输出日志内容

    05 console.info(Node.js - console.info 方法); 输出信息内容

    上面的代码演示了Node.js平台中console.log方法与console.info方法

    的应用,通过这两个方法向控制台输出内容完全一致的字符串,下面是这两个方法

    的语法:

    语法:console.log([data], [...]); 打印输出1行数据

    语法:console.info([data], [...]); 同console.log方法

    console.log方法的功能是向控制台实现标准输出,该方法也可以像C语言的

    printf一样接受多个参数。而console.info方法的功能与console.log方

    法是完全一致的,输出的效果也是一致的。

    下面向读者演示使用基于JavaScript语言的集成开发软件WebStorm开发

    Node.js平台应用的方法,如图1.7所示。图1.7 应用WebStorm集成开发软件运行js脚本文件

    下面我们看一下图中源代码窗口,如图1.8所示。

    图1.8 WebStorm集成开发软件源代码窗口

    我们单击工具栏中的Debug ‘ch01-log-info.js’按钮,查看调试运行后结

    果输出,如图1.9所示。图1.9 WebStorm集成开发软件调试输出窗口

    从图中可以看到,使用console.log与console.info这两个方法输出的

    结果是完全一致的,说明这两个方法实现的功能是完全一致的。

    提示:在Windows环境下与Ubuntu环境下使用WebStorm集成开发软件开发

    Node.js平台应用的方法大同小异,读者可以到jetBrain.com官方网站上下载相应

    的WebStorm软件版本。配置WebStorm软件支持Node.js平台的方法这里就不具体讲

    解了,读者可以参考互联网上的相关资源,刚刚起步的读者如果遇到问题也可以发

    邮件联系我们进行咨询。

    1.3 字符串格式化的应用

    对于任何一种编译执行或解释执行的编程语言来讲,数据格式化输出都是最基

    本的功能之一,所谓格式化就是将数据的表现形式固定为某一种常用格式,例如自

    然数、保留三位小数、日期、时间、IP地址等。在Node.js平台下,数据格式化主

    要针对以下三种类型,分别是字符型格式、数值型格式和JSON数据交换格式。从本

    例开始,我们将通过三节分别向读者进行介绍。

    首先,在本节介绍一下字符型格式化字符串的使用方法,本例ch01.format-

    string.js主要代码如下:

    01 02 ch01.format-string.js

    03

    04 console.log(%s, This is a format-string Note.js Program.); %s - String

    05 console.log(%s %s %s, You can, connect, several strings.);

    06 console.log(%s, You can, connect, several strings.);

    07 console.log(%s:%s, object, string);

    08 console.log(%s-%s, object, string);

    09 console.log(%);

    10 console.log(%%);

    【代码分析】

    第04行是字符型格式的应用,将log方法中的第1个参数设定为“%s”,则第

    2个参数会按照字符型格式进行输出;第05行是字符串连接的应用,将log方法中

    的第1个参数设定为“%s %s %s”,将会把第2个到第4个参数连接起来并按照字符

    型格式进行输出;第06行与第05行实现的功能一样,不同的是将log方法中的第1

    个参数设定为“%s”与设定为“%s %s %s”的输出效果是完全一样的;在第07行与

    第08行中,我们在log方法中的第1个参数中加入特殊字符(“:”与“-”),它

    将会按照其位置在格式化字符串中进行输出;在第09行与第10行中,我们看到了特

    殊字符“%”的使用,在这样使用“%%”时,第一个“%”字符将会被当作占位符进

    行处理。

    图1.10是本例程调试输出后的结果。图1.10 字符型格式化调试输出结果

    提示:在Node.js框架的官方文档中指出,单个百分号“%”在格式化字符串中

    使用时,将占用一个占位符空间,但如果占位符没有对应的参数,则占位符不会被

    替换。

    1.4 数值型格式化的应用

    延续上一节的内容,本节我们将通过一个例程来介绍在Node.js平台下使用数

    值型格式化字符串的具体方法。本例ch01.format-data.js主要代码如下:

    01

    02 ch01.format-data.js

    03

    04 console.log(8+0.8); 数值运算

    05 console.log(%d, 8, 8.8); 数值格式化输出

    06 console.log(%d-%d, 8.8, 8.0); 含有特殊字符的格式化

    07 console.log(%d, 8+8, 8-8, 88, 88); 数值运算格式化输出

    08 console.log(%d, 8+8);

    09 console.log(80); 除0运算【代码分析】

    第04行是直接在log方法中将参数定义为数值(非字符串),将会把该数值

    直接进行输出;第05行是标准数值型格式化的应用,将log方法中的第1个参数设

    定为“%d”,将会把从第2个参数开始的参数依次按照数值型格式进行输出;在第06

    行中,我们在log方法中的第1个参数中加入特殊字符(“-”),它将会按照其

    位置在格式化字符串中进行输出;在第07行中,我们看到了一个简单的四则运算数

    值型格式化输出;在第08行中,我们测试了一下使用数值型格式化输出字符串的效

    果,输出结果为“NaN”,表示格式化出现异常;在第08行中,我们测试了除数为0

    时的结果,与其他编程语言有所不同的是,输出结果为“Infinity”。

    图1.11是本例程调试输出后的结果。

    图1.11 数据型格式化调试输出结果

    提示:关于第04行,在Node.js平台的官方文档中有这样解释,如果第一个参

    数没有定义格式化类型,则将会把该参数进行必要的运算后转化为字符串格式进行

    输出。在实际应用中,开发者几乎不用考虑该转化,因为最终在控制台输出的就是

    字符串格式。

    1.5 JSON数据交换格式应用本节我们将通过一个例程来介绍在Node.js平台下使用JSON数据交换格式的具

    体方法。有关JSON数据交换格式的简要介绍,读者可以参看本节后面的提示部分的

    内容。本例ch01.format-json.js主要代码如下:

    01

    02 ch01.format-json.js

    03

    04 console.log(%j, {OS:Windows,Version:7.1,Language:[English,Chinese]});

    05 var v_json = { JSON交换格式定义

    06 OS:Windows,07 Version:7.1,08 Language:[English,Chinese]

    09 }

    10 console.log(%j, v_json);

    【代码分析】

    第04行是直接在log方法中将第一个参数定义为JSON格式(“%j”),然后

    把第二个参数定义的JSON数据进行输出;第05~10行是另一种实现方式,首先定义

    了一个JSON格式的变量并对该变量进行赋值,然后再由log方法对该变量进行输

    出。

    图1.12是本例程调试输出后的结果。从图中可以看到,两种方法执行后的效果

    是完全一致的,可见Node.js平台对JSON数据交换格式有很好的支持。图1.12 JSON对象格式化调试输出结果

    提示:JSON的英文全称为JavaScript Object Notation,是一种轻量级的数

    据交换格式。JSON是JavaScript的一个子集,是一种全新的、与编程语言无关的、易于解析和生成的文本格式。基于以上这些特点,JSON数据已经无可厚非地成为了

    一种用于网络数据传输的标准数据交换格式。

    1.6 测试特殊运算符如何取值

    如果读者有学习过C、Java和JavaScript这样的基础编程语言,一定知道对于

    含有比较运算符或逻辑运算符的表达式,同普通表达式一样会有一个表达式值。那

    么在Node.js平台下,比较运算符和逻辑运算符的特性是怎样的呢?在本节我们就

    将通过一段代码来测试说明在Node.js平台下,特殊运算符是如何进行判断取值

    的。本例ch01.format-logic.js主要代码如下:

    01

    02 ch01.format-logic.js

    03

    04 var a=0;

    05 var b=1;

    06 console.log(a==b); 使用比较运算符,输出false

    07 console.log(a>=b); 使用比较运算符,输出false

    08 console.log(a<=b); 使用比较运算符,输出true

    09 console.log(a==0 b==1); 使用逻辑运算符,输出true

    【代码分析】

    第06~08行是使用比较运算符(“==”、“>=”、“<=”)进行运算,然后输

    出运算结果(true或者false);第09行是综合使用比较运算符(“==”)与逻辑

    运算符(“”:逻辑“与”运算符)进行运算,然后输出运算结果(true或者

    false)。图1.13是本例程调试输出后的结果。从图中输出结果可以看到,运算法比较运

    算与逻辑运算的结果为true和false两个真值,基本延用了C、Java、JavaScript

    等编程语言的传统规范。

    图1.13 运算符调试输出结果

    提示:在Node.js平台下,关于比较运算符与逻辑运算符的详细用法,读者可

    以借鉴JavaScript语言,两者基本上是完全一致的。

    1.7 特殊格式化参数应用

    在前面几节中,我们向读者演示了几种常规数据格式化的应用。其实在实际应

    用开发过程中,我们可能还会碰到许多特殊情况,例如:当仅有第一个参数出现,其写法有类似“%8s”这样的格式化参数时,Node.js平台会如何处理呢?本节我们

    将通过一段代码来说明在Node.js平台下关于特殊格式化参数的用法。本例

    ch01.format-argument.js主要代码如下:

    01

    02 ch01.format-argument.js

    03

    04 console.log(%s, argument);

    05 console.log(%s);06 console.log(%d, 8);

    07 console.log(%d);

    08 console.log(%8s);

    09 console.log(%8d);

    10 console.log(%8s, %8s);

    11 console.log(%8d, 8);

    【代码分析】

    第04~05行是“%s”的比较用法,如第05行单独使用“%s”且仅有一个参数

    时,Node.js平台将会把“%s”当做字符串直接输出;第06~07行是“%d”的比较

    用法,其输出结果与“%s”是一致的;第08~09行是格式化参数的特殊用法,如果

    格式化参数写成如“%8s”或“%8d”这样的格式,Node.js平台则会把它当做字符

    串来处理;第10~11行告诉我们,即使console.log方法含有第2个参数,第1个

    参数(如写成“%8s”或“%8d”这样的格式)也不会具有数据格式化功能,仍将直

    接当做字符串来处理并输出。

    图1.14是本例程调试输出后的结果。

    图1.14 格式化参数调试与输出结果

    提示:在Node.js平台下,单独使用console模块进行数据格式化的功能比起Java和JavaScript语言还是要弱一些的,一般需要借助于JavaScript语言才能完

    成更强大的操作,在后续的例程中我们会逐步介绍给读者。

    1.8 斐波那契(Fibonacci)数列应

    用

    通过前面几节的介绍,读者应该对Node.js平台的控制台信息输出有了一定的

    了解。那么在本节中,我们将著名的Fibonacci数列融合到Node.js平台控制台开发

    中,向读者演示使用console.info方法输出Fibonacci数列的过程。

    本例ch01.console-fibonacci.js主要代码如下:

    01

    02 ch01.console-fibonacci.js

    03

    04 console.info(\n);

    05 console.info(------Fibonacci数列应用------);

    06 console.info(\n);

    07 var strFibonacci; 定义字符串变量,用于输出Fibonacci数列

    08 var i=1, j=1, s=i+j; 初始化变量i,j

    09 strFibonacci = 输出Fibonacci数列>>> 1 1 ; 初始化Fibonacci数列

    10 循环结束判断条件

    11 while(s <= 1000)

    12 {

    13 strFibonacci = strFibonacci + s + ;

    14 i = j;

    15 j = s;

    16 s = i + j; Fibonacci数列:F(n) = F(n-1) + F(n-2)

    17 }

    18 console.info(strFibonacci); 打印输出Fibonacci数列19 console.info(\n);

    【代码分析】

    第07行定义了保存Fibonacci数列所需的变量strFibonacci;第08行定义了三

    个变量并进行了初始化(我们知道Fibonacci数列的第1个和第2个数列项均为数值

    1,之后的数列项基于它进行叠加);第09行对变量strFibonacci进行初始化;第

    11~17行即实现Fibonacci数列的具体算法,感兴趣的读者可以参考有关讲述

    Fibonacci数列算法的书籍;其中第13行用于实现将计算出的数列项叠加保存在变

    量strFibonacci中;第18行实现输出Fibonacci数列。

    图1.15是在Ubuntu环境下本例程调试输出后的结果。

    图1.15 Fibonacci数列输出结果

    提示:在Node.js平台下,使用console.info方法输出后会自动换行,因此

    我们无法计算出一个数列项随几进行输出。本例采用变通的方法,将叠加计算出的

    每一个数列项保存在一个变量中,全部计算完毕后再一次性输出数列。

    1.9 错误与警告提示应用当用户在界面中输入发生错误时,系统通常会给出一个错误或警告提示。如果

    想在Node.js平台中实现这个错误或警告提示功能,可以通过console.error与

    console.warn这两个方法来实现,下面是一个演示这种错误提示的例程。

    本例ch01.error-warn.js主要代码如下:

    01

    02 ch01.error-warn.js

    03

    04 var fs = require('fs'); 引入fs模块

    05 var file = 'chapter01error-warn.txt'; 定义文件源

    06 var encoding = 'UTF-8'; 定义字符编码

    07 fs.readFile(file, encoding, function(err, data) { 读取本地文件函数

    08 if(err) {

    09 console.error(error - \n %s, err);

    10 console.warn(warn - \n %s, err);

    11 } else {

    12 console.log(data);

    13 }

    14 });

    【代码分析】

    这个例程主要功能为读取本地文本文档,并将其中内容进行输出。下面我们只

    看第09~10行,这两行分别使用console.error方法与console.warn方法将

    err参数的内容输出到终端。关于console.error方法与console.warn方法的

    语法如下:

    语法:console.error([data], [...]); 打印输出1行错误数据.

    语法:console.warn([data], [...]); 同console.error方法

    图1.16是本例程调试输出后的结果,从中可以看到,使用console.error方

    法与console.warn方法运行效果是完全一致的,这两个方法实现的功能也是一样的。

    图1.16 错误信息方法、警告信息方法调试与输出结果

    提示:在Node.js平台下,console.error方法与console.log方法一

    样,在console.error方法中也可以通过参数指定输出字符串的格式,可使用参

    数与console.log方法中使用的参数相同。

    1.10 重定向标准错误输出流

    Node.js平台的控制台操作同样可以实现重定向标准错误输出流的功能。在执

    行node命令时,可以指定命令的标准错误输出流形式,缺省状态是控制台屏幕,也

    可以为文件重定向。本例我们实现重定向标准错误输出流到文件的功能。

    本例ch01.stderr-file.js主要代码如下:

    01

    02 ch01.stderr-file.js

    03

    04 var fs = require('fs'); 引入fs模块

    05 var file = 'chapter01not-found.txt'; 定义文件源

    06 var encoding = 'UTF-8'; 定义字符编码

    07 fs.readFile(file, encoding, function(err, data) { 读取本地文件函数08 if(err) {

    09 console.error(error - \n %s, err);

    10 console.warn(warn - \n %s, err);

    11 } else {

    12 console.log(data);

    13 }

    14 });

    【代码分析】

    这个例程主要功能是通过读取一个本地不存在的文本文档来产生错误,并将系

    统错误提示输出到本地错误文件中。我们看第05行,定义了一个本地不存在的文本

    文档(文件名为not-found.txt);再看第07行,通过readFile函数来读取该文

    档,由于该文档不存在,所以系统会报错。

    在控制台使用node命令重定向标准错误输出流到文件的语法如下:

    语法:node js-filename.js 2> error.log

    图1.17是在控制台使用重定向标准错误输出流到文件的方法。

    图1.17 在控制台使用重定向标准错误输出流到文件的方法

    输出到本地错误日志文件(文件名为error.log)的内容如图1.18所示。图1.18 本地错误日志文件的内容

    提示:在Node.js平台下,任何运行程序引发的错误信息均可被重定向到某个

    文件中。当输出目标是文件时,console模块方法是同步执行的,这样可以防止过

    早退出时丢失信息。console函数根据输出目标的不同分为“同步异步”两种方

    式,在平常使用中用户不需要太担心“阻塞非阻塞”的差别,除非需要记录大量数

    据。

    1.11 查看Node.js对象的属性和方

    法

    在Node.js平台下,可以使用console.dir方法实现快速查看对象实例所包

    含属性和方法的功能。在我们不知道某个Node.js对象实例所包含的属性和方法

    时,这个功能还是非常实用的。在这个例程中,我们看一下console.dir方法对

    于不同的对象类型是如何进行输出的。

    本例ch01.obj-dir.js主要代码如下:

    01

    02 ch01.obj-dir.js

    03

    04 console.dir(123); 使用console.dir方法查看整型对象05 console.dir(abc); 使用console.dir方法查看字符串对象

    06 console.dir({abc:123}); 使用console.dir方法查看JSON对象

    07 console.dir(1+23+1); 使用console.dir方法查看表达式对象

    08 console.dir(console); 使用console.dir方法查看Node.js核心模块

    【代码分析】

    第04行实现的是查看整型对象(123)的功能,其输出结果仍是整型对象;第

    05行实现的是查看字符串对象(“abc”)的功能,其输出结果仍是字符串对象;第

    06行实现的是查看JSON类型对象({“abd”:123})的功能,其输出结果仍是JSON

    类型对象;第07行实现的是查看运算表达式对象(1+23+1)的功能,其输出结果

    是该运算表达式的计算结果(本例程计算结果等于8);第08行实现的是查看

    console核心模块对象的功能,console.dir方法将会输出console对象所包含

    的全部属性和方法明细。

    图1.19是本例程调试输出后的结果。

    图1.19 使用console.dir方法查看对象实例的属性和方法提示:如果查阅Node.js文档规范,我们会知道console.dir方法实际上在

    底层是通过对obj对象使用util.inspect方法、并将结果字符串输出到stdout来

    实现的。关于util模块的方法我们会在后面章节做详细介绍。

    1.12 时间计时器应用

    Node.js平台的console模块提供了时间计时器的功能,分别是通过

    console.time与console.timeEnd这两个方法组合使用来完成的。在本节的

    例程中,我们通过console.time与console.timeEnd这两个方法来实现计算

    代码执行时间的功能并进行屏幕输出。

    本例ch01.time-timeend.js主要代码如下:

    01

    02 ch01.time-timeend.js

    03

    04 var n=0;

    05 console.time('10000x10000-times'); 使用console.time方法开始时间计时器

    06 for(var i=0; i<10000; i++) {

    07 for(var j=0; j<10000; j++) {

    08 n++;

    09 }

    10 }

    11 console.timeEnd('10000x10000-times'); 使用console.timeEnd方法结束时间计时器

    12 console.info(n);

    【代码分析】

    该例程首先定义一个整型变量n,初始值设定为0,然后通过一个简单的双重循

    环体来叠加增加变量n的值,实际上n值也相当于记录了循环叠加的次数。第05行通

    过console.time方法标记一个时间开始点,并带有一个字符串('10000x10000-times')参数。关于console.time方法的语法如下:

    语法:console.time(label) mark a time

    第06~10行实现的是双重循环体来叠加增加变量n值的功能,也相当于记录了循

    环叠加的次数,实际上时间计时器记录的就是这段时间间隔;第11行通过

    console.timeEnd方法标记一个时间结束点并将时间记录值进行输出(时间单位

    为毫秒ms),该方法同样带有一个字符串('10000x10000-times')参数;

    console.timeEnd方法的语法如下:

    语法:console.timeEnd(label) Finish timer, record output.

    第12行通过变量n的值来输出循环计算的次数。

    图1.20是本例程调试输出后的结果。

    图1.20 时间计时器应用调试输出

    提示:console.time与console.timeEnd这两个方法都仅使用一个参

    数,其参数值可以为任何字符串形式,但需要读者注意的是这两个方法所使用的参

    数字符串必须相同,这样才能正确地统计出开始时间与结束时间之间所经过的毫秒

    数。1.13 查看当前调用栈的方法

    如果用户有过C、Java等高级语言的开发经验,一定知道在调试程序时debug工

    具会将当前程序调用栈的情况展示给用户,方便用户了解程序的运行情况。同样,console模块的trace方法实现了向标准错误流输出当前调用栈的功能。在本节例

    程中,我们研究一下console.trace方法具体向用户输出了什么内容。

    本例ch01.console-trace.js主要代码如下:

    01

    02 ch01.console-trace.js

    03

    04 console.trace; 第一次调用console.trace方法

    05 console.trace(start); 第二次调用console.trace方法

    06 var fs = require('fs');

    07 var file = 'chapter01not-found.txt';

    08 var encoding = 'UTF-8';

    09 fs.readFile(file, encoding, function(err, data) {

    10 console.trace(fs-start); 第三次调用console.trace方法

    11 if(err) {

    12 console.error(error - \n %s, err);

    13 console.warn(warn - \n %s, err);

    14 } else {

    15 console.log(data);

    16 }

    17 console.trace(fs-end); 第四次调用console.trace方法

    18 });

    19 console.trace(end); 第五次调用console.trace方法

    【代码分析】

    以上代码演示了在代码的不同位置使用console.trace方法的输出效果。该例程总体上是一个读取本地文件的程序,我们分别在代码执行的不同位置调用

    console.trace方法,目的就是研究一下当前调用栈中的具体内容是什么。关于

    console.trace方法的语法说明如下:

    语法:console.trace(message, [...])

    console.trace方法的功能是打印当前位置的栈,并跟踪到标准错误输出流

    (process.stderr)。

    第04行直接使用console.trace方法进行输出,而且不使用参数;第05行使

    用带有一个字符串start参数console.trace方法进行输出;从图1.21中可以看

    到,第04行使用不带参数与第05行使用带参数的console.trace方法输出当前堆

    栈内容的结果是一致的,唯一一点小区别就是带参数的console.trace方法在输

    出时会在trace字符串后加上该参数。

    第06~18行实现的是一个通过fs.readFile方法读取本地文本文件并记录错

    误的功能;其中分别在第10行与第17行使用console.trace方法进行输出,这两

    个方法使用不同的参数(fs-start与fs-end);从图1.21中可以看到,第10行与

    第17行使用console.trace方法输出当前堆栈内容的结果是一致的,但与第04、05行的输出的堆栈内容是有区别的,在执行第10行与第17行时,当前堆栈是在

    fs.js模块中,由Node.js官方文档可以知道目前程序正在使用文件系统(fs)模

    块;第19行是在代码运行最后执行一次console.trace方法,带有一个字符串

    end参数,从图1.21中调试输出结果可以看到,当前堆栈已经从文件系统(fs)模

    块中跳出,返回到系统模块中了。图1.21 console.trace方法调试输出

    提示:console.trace方法不使用参数时,其调试输出结果仅显示trace字

    符串。

    1.14 对表达式结果进行评估

    Node.js平台console模块的assert方法实现了对表达式结果进行评估的功

    能。在本节的例程中,我们通过一段代码向读者演示如何应用console.assert方

    法实现对表达式结果进行评估的功能。

    本例ch01.console-assert.js主要代码如下:01

    02 ch01.console-assert.js

    03

    04 var i=0; 定义变量i

    05 var j=1; 定义变量j

    06 console.assert(i==0, OK); 评估表达式“i==0”

    07 console.assert(i==j, throw an exception); 评估表达式“i==j”

    【代码分析】

    该例程比较简单,我们首先定义了两个整型变量,然后通过console.assert

    方法对这两个整型变量进行断言判断。关于console.assert方法的语法说明如

    下:

    语法:console.assert(expression, [message], [...])

    console.assert方法的功能是进行断言判断,如果expression执行结果为

    false,则抛出一个带上message提示信息的AssertionError。

    第04~05行定义了两个值不相等的整型变量;第06行使用console.assert

    方法对“i==0”这个表达式进行判断,并带有一个OK参数;从图1.22中可以看到,第06行的console.assert方法没有对执行结果进行输出,我们知道

    对“i==0”这个表达式判断的结果为true,所以console.assert方法对于判断

    结果为“真”的表达式不执行结果输出;第07行使用console.assert方法

    对“i==j”这个表达式进行判断,并带有一个throw an exception参数。图1.22 console.assert方法调试输出

    从图1.22中可以看到,根据throw an exception参数提示知道第07行的

    console.assert方法抛出了异常输出,从对整型变量i和j的赋值可以得

    出“i==j”这个表达式判断的结果为false,所以console.assert方法对于判断

    结果为“假”的表达式抛出了异常输出。

    提示:从Node.js官方文档中的解释可以知道,console.trace方法与

    assert.ok方法相同,实际上console.trace方法在底层的实现就是通过

    Assert模块的assert.ok方法完成的。

    1.15 读取命令行输入信息

    在前面的例子中,向读者演示了Node.js平台通过console模块向控制终端输出

    信息的功能。那么Node.js平台能不能实现从控制台读取用户输入的功能呢?答案

    是肯定的。

    Node.js平台实现了几种从控制台读取用户输入的方法。在本节例程中,我们

    通过一个例程向读者演示如何应用readline模块的question方法实现从控制台读取一行用户输入的功能。

    本例ch01.console-readline.js主要代码如下:

    01

    02 ch01.console-readline.js

    03

    04 var readline = require('readline'); 引入readline模块

    05 var rl = readline.createInterface({ 初始化rl对象

    06 input: process.stdin,07 output: process.stdout

    08 });

    09 rl.question(What is your name?, function(answer) { 读取命令行输入信息

    10 Log the answer in a database

    11 console.log(My name is , answer);

    12 rl.close;

    13 });

    14 rl.question(How old are you?, function(answer) { 读取命令行输入信息

    15 Log the answer in a database

    16 console.log(I'm , answer);

    17 rl.close;

    18 });

    【代码分析】

    在Node.js平台下使用readline模块,首先需要使用require方法加载该模

    块,如第04行所示。

    代码:var readline = require('readline');

    加载好readline模块后,需要创建具体readline模块的对象(本例为变量

    rl),如第05~08行所示。使用readline模块的createInterface方法来实

    现,并在该方法内定义好标准输入流和标准输出流。关于readline.createInterface方法的语法说明如下:

    语法:readline.createInterface(options)

    createInterface方法创建一个readline模块的接口实例,并接受一个

    object类型参数“options”,该参数可传递以下几个值。

    input:要监听的可读流(必需)。

    output:要写入readline的可写流(必需)。

    completer:用于Tab自动补全的可选函数。

    terminal:如果希望input和output流像TTY(计算机终端设备)

    一样,那么通过传递参数true来实现,并且经由ANSIVT100转码,默认情

    况下检查isTTY是否在output流上实例化。

    从第06行与第07行可以看到,本例程是通过使用input和output两个参数值来

    实现的;在预定义工作做好后,使用定义好的变量rl引用question方法进行从控

    制台读取一行用户输入的操作。关于readline.question方法的语法说明如下:

    语法:readline.question(query, callback)

    question方法预先提示指定的query,然后在终端接受到用户输入后再触发

    指定的callback(回调函数)继续执行;第09~13行与第14~18行定义了两个使用

    readline.question方法的操作,分别实现了两段从控制台读取一行用户输入的

    功能;从图1.23中可以看到,第09~13行在询问了用户姓名后,通过answer参数接

    受用户在控制台的输入,并通过console.log方法配以一段文字将其显示在控制

    台终端中。

    同样从图1.23中可以看到,第14~18行实现了与前一段代码相同的功能,但是

    在控制台终端中并没有得到显示,原因是在执行readline.question方法的回调

    函数过程中,执行了第12行rl.close方法后就返回到了系统上下文环境下,所以

    第14~18行并没有被执行。图1.23 读取命令行输入信息

    提示:

    1. Node.js官方文档中关于readline.createInterface方

    法“options”参数使用“terminal”值的解释比较晦涩,本书尽量做到按照官方

    文档的原意向读者进行解读。

    2. Node.js官方文档对readline.question方法“query”参数做了进一步

    描述,指出在显示指定的“query”参数给用户后,当用户的应答被输入后,就触发

    了指定的callback(回调函数)并返回。

    1.16 阶乘运算输出

    上一节向读者演示了从控制台命令行读入用户输入信息的方法,那么在本节我

    们借助这个方法实现一个Node.js平台下的阶乘运算输出应用。说起阶乘运算读者

    肯定不会陌生,在概率与统计计算中阶乘是最常用的功能之一。通过计算机程序实

    现阶乘运算一般有常规的循环计算方法与递归计算方法,在本节的例子中我们使用

    简洁易读的递归计算方法。

    本例ch01.console-factorial.js主要代码如下:

    01

    02 ch01.console-factorial.js03

    04 console.info(\n);

    05 console.info(------阶乘计算------);

    06 console.info(\n);

    07 var iNum, iFactorial=1; 定义并初始化变量

    08 var strFactorial; 定义字符串变量,用于阶乘运算结果输出

    09 从控制台读取用户输入

    10 var readline = require('readline');

    11 var rl = readline.createInterface({

    12 input: process.stdin,13 output: process.stdout

    14 });

    15 rl.question(请输入阶乘运算起始数值:\nn = , function(iNum) {

    16 计算阶乘结果

    17 strFactorial = iNum + ! = + factorial(iNum);

    18 console.info(strFactorial); 输出计算结果

    19 console.info(\n);

    20 rl.close;

    21 });

    22

    23 定义阶乘运算的递归方法

    24

    25 function factorial(n) {

    26 if(n > 0)

    27 {

    28 if(n == 1)

    29 {

    30 iFactorial = 1;

    31 }

    32 else

    33 {

    34 iFactorial = n factorial(n-1);35 }

    36 }

    37 return iFactorial;

    38 }

    【代码分析】

    该例程首先接受一个用户输入信息,用于定义阶乘运算的初始数值,然后通过

    递归计算得出阶乘运算结果并输出。第07行定义了两个阶乘计算的变量,其中变量

    iNum用于接受用户输入数值,变量iFactorial用于保存阶乘计算结果;第08行定义

    了一个字符串变量strFactorial,用于保存阶乘计算输出;第10~21行用于接受用

    户输入的阶乘运算初始数值,并调用factorial方法进行计算;其中第17行通过

    将factorial方法的返回值(即阶乘运算结果)保存到变量strFactorial中,最

    后由第18行通过console.info方法进行输出;第25~38行定义了通过递归计算

    阶乘的factorial方法,感兴趣的读者可以参考有关讲述阶乘运算与递归算法的

    书籍;其中第37行用于将阶乘运算的结果进行返回。

    图1.24是在Ubuntu环境下本例程调试输出的结果。

    图1.24 阶乘运算输出

    提示:本节与前面1.8节一样,由于使用console.info方法输出后会自动地换行,因此我们将阶乘计算出的结果信息保存在一个变量中,全部计算完毕后再一

    次性进行输出。

    1.17 向控制台输出组合控制键

    在很多情况下,应用程序需要模拟组合控制键操作(如复制、粘贴、撤销等)

    来代替用户完成一些键盘操作功能。而在Node.js平台下,通过readline模块的

    write方法可以实现向控制台输出控制键的功能。本节我们通过一个例程向读者

    演示如何应用readline.write方法,来实现对向控制台输出的内容进行撤销操作

    的功能。

    本例ch01.console-write.js主要代码如下:

    01

    02 ch01.console-write.js

    03

    04 console.info('Node.js - readline.write Usage');

    05 var readline = require('readline'); 引入readline模块

    06 var rl = readline.createInterface({ 初始化rl对象

    07 input: process.stdin,08 output: process.stdout

    09 });

    10 rl.write('Delete me! Wait for 3 seconds...');

    11 var timeoutLength = 3 1000; 3秒

    12 var timeout = setTimeout(function { 调用setTimeout方法

    13 模仿ctrl+u快捷键,删除之前所写行

    14 rl.write(null, {ctrl:true, name:'u'});

    15 }, timeoutLength);

    【代码分析】第04行通过console.info方法向控制台终端输入一行内容提示文字;第05

    ~09行执行的是加载readline模块并进行初始化定义的操作;第10行使用

    readline模块的write方法来向控制台终端写入一行文字内容,关于

    readline.write方法的语法如下:

    语法:readline.write(data, [key])

    write方法将参数data的内容写入到控制台标准输出流,参数key是一个代表

    键序列的对象,当终端是一个TTY(计算机终端设备)时可用;第11行通过变量

    timeoutLength定义了一段时间间隔(时长为3秒);第12~15行借助

    setTimeout方法实现了经过一段时间延迟后,具体是通过第14行中的

    readline.write方法执行向控制台模拟输出撤销操作快捷键、并删除之前写入的

    一行文字内容的功能;其中readline.write方法的key参数为一个JSON对象

    ({ctrl:true, name:'u'}),该对象定义了一个组合控制键“ctrl+u”,该组

    合控制键实现了撤销上一步操作的功能。

    图1.25和图1.26是本例程调试输出后的结果。

    图1.25 向控制台输出组合控制键(一)图1.26 向控制台输出组合控制键(二)

    从以上两张结果图中可以看到,图1.25中通过readline.write方法向控制

    台终端写入的数据,在经过一段时间延迟后,再次通过readline.write方法以向

    控制台终端写入具有撤销操作的组合控制键的形式实现了删除操作的功能,撤销操

    作后结果如图1.26所示。

    提示:

    1.关于setTimeout方法的具体应用方法可以参考JavaScript文档,实际上

    本例程中的setTimeout方法是属于JavaScript语言范畴之中的。

    2.如果在readline.write中执行了暂停操作,则会重置控制台标准输入

    流,直到执行恢复操作后才会继续进行写入操作。

    1.18 模拟一个简单的控制台界面

    Node.js平台的readline模块提供了很多实用的方法,可以实现足够强大的应

    用。本节通过一个例程向读者演示如何应用readline模块提供的方法,来模拟一个

    简单的控制台界面应用。

    本例ch01.console-tinyCLI.js主要代码如下:

    01 02 ch01.console-tinyCLI.js

    03

    04 var readline = require('readline'); 引入readline模块

    05 rl = readline.createInterface( 初始化rl对象

    06 process.stdin,07 process.stdout

    08 );

    09 rl.setPrompt('NodeJS> '); 定义模拟控制台命令行提示符

    10 rl.prompt; 初始化模拟控制台

    11 rl.on('line', function(line) { 激活readline模块的line事件

    12 switch(line.trim{

    13 case 'name':

    14 console.log('king!');

    15 break;

    16 case 'code':

    17 console.log('Node.js!');

    18 break;

    19 case 'time':

    20 console.log('2015!');

    21 break;

    22 default:

    23 console.log('Say what? I might have heard `' + line.trim + '`');

    24 break;

    25 }

    26 rl.prompt;

    27 }).on('close', function { 激活readline模块的close事件

    28 console.log('Have a great day!');

    29 process.exit(0); 退出进程

    30 });

    【代码分析】

    第04~08行执行的是加载readline模块并进行初始化定义的操作;第09行通过readline.setPrompt方法模拟输出控制台的命令行提示符,本例程提示符

    为“NodeJS>”,关于readline.setPrompt方法的语法说明如下:

    语法:readline.setPrompt(prompt, length)

    其中,prompt参数用来定义命令行提示符,length参数用来定义命令行提示符

    的长度,length参数为可选参数,具体效果如图1.27所示。

    图1.27 模拟控台tinyCLI应用效果(一)

    第10行通过readline.prompt方法模拟实现控制台,等待接收用户的输入,关于readline.prompt方法的语法说明如下:

    语法:readline.prompt([preserveCursor])

    其中,当preserveCursor参数设置为true时,用来阻止命令行提示符的光标

    位被重置为0,通常preserveCursor参数可以不用设定。

    第11行通过readline模块提供的line事件来激发命令行输入功能,激活事件的

    方法为Node.js平台Event模块提供的on方法,有关Event模块的详细介绍放在后

    续章节,此处读者了解on方法的功能即可;第12~24行通过switch选择语法,用

    来实现接收用户输入后模拟控制台所做出的应答,具体效果如图1.28所示。图1.28 模拟控台tinyCLI应用效果(二)

    从图1.28中可以看到,在命令行提示符“NodeJS>”出现后,用户依次输入

    name、code、time,控制台依次向用户反馈king、Node.js、2015;而当用户无

    输入直接回车时,控制台则会向用户反馈默认定义的字符串(Say what? I might

    have heard),表示用户没有任何输入;以上这些与我们在第12~24行中实现的结

    果预期是完全一致的。

    第26行通过readline.prompt方法用来实现在接受完一次用户输入后,再次

    返回模拟控制台命令行,等待用户下一次输入;如果没有该行,模拟控制台在接受

    完一次用户输入后会失去命令行界面,读者可以自行验证一下;第27~29行用来实

    现退出模拟控制台的操作,此处通过readline模块提供的close事件来激发退出模

    拟控制台的操作,并且使用process模块的exit方法实现退出的功能;另外,本

    例程在模拟控制台退出前向控制台界面输出一段字符串(Have a great day!),用于提示退出操作已完成。

    提示:关于readline模块的事件说明及具体应用方法可以参考Node.js文档,实际上通过本例程可以看到使用readline模块可以实现控制台的绝大多数功能。

    1.19 输出水仙花数通过前面若干节的介绍,相信读者对于控制台模块的应用有了一定的了解。从

    本节开始,我们通过对几个常见的数学算法问题使用Node.js框架方式编程求解,来加深读者对控制台模块的理解。

    本节我们来尝试使用Node.js框架方式编程求解数字100至999之间的水仙花

    数,所谓水仙花数就是一个三位自然数的百位、十位和个位数字的立方和。在数学

    计算上我们不难理解其计算方法,那么通过程序如何实现呢?

    本例ch01.console-narcissus.js主要代码如下:

    01

    02 ch01.console-narcissus.js

    03

    04 var m, a, b, c, sum;

    05 for(m=100; m<1000; m++) { 循环判断100~999整数中的水仙花数

    06 a = parseInt(m100); 计算出百位数

    07 b = parseInt((m-a100)10); 计算出十位数

    08 c = parseInt(m-a100-b10); 计算出个位数

    09 sum = aaa + bbb + ccc;

    10 if(m == sum) { 判断是否满足水仙花规则

    11 console.info(%d, m);

    12 }

    13 }

    【代码分析】

    第04行定义了验证计算需要的变量,其中变量m用于for循环计数,变量a、b、c分别用于保存百位、十位和个位数字,变量sum用于保存计算结果;第06~08行分

    别用于计算出三位自然数的百位、十位和个位数字,其中parseInt方法的功能是

    对计算结果的小数进行取整;第09行将百位、十位和个位数字的立方和计算结果保

    存在变量sum中;第10~12行通过条件判断语句来验证该自然数是否满足水仙花数

    的条件,如果判断结果为真,则使用console.info方法进行直接打印输出。图1.29是在Ubuntu环境下本例程调试输出的结果。

    图1.29 水仙花数输出

    提示:parseInt方法属于JavaScript语言范畴,当其用于对一个小数进行

    取整时,读者要注意的是其取整过程是将小数部分直接舍弃,而非四舍五入。

    1.20 输出质数

    本节我们来尝试使用Node.js框架方式编程求解质数,所谓质数就是一个整

    数,该整数只能被1和其自身整除。关于质数的概念读者应该是比较熟悉的,那么通

    过程序如何实现呢?

    本例ch01.console-primeNum.js主要代码如下:

    01

    02 ch01.console-primeNum.js

    03

    04 var i, j, iNum, strPrimeNum;

    05 var bFlag; 定义该变量,用于标记是否为质数

    06 var readline = require('readline');

    07 var rl = readline.createInterface({

    08 input: process.stdin,09 output: process.stdout

    10 });11

    12 用户输入一个整数作为上限,通过程序计算从2开始到该整数之间的全部质数

    13

    14 rl.question(Please enter number? , function(iNum) {

    15 Calculate prime number

    16 strPrimeNum = 2 ;

    17 for(i=3; i<=iNum; i++) 利用for循环计算质数

    18 {

    19 bFlag = true;

    20 for(j=2; j
    21 {

    22 if(i%j == 0) 通过if条件判断是否满足质数的条件

    23 {

    24 bFlag = false;

    25 break;

    26 }

    27 }

    28 if(bFlag == true)

    29 {

    30 strPrimeNum = strPrimeNum + i + ; 将质数保存在一个字符串变量中

    31 }

    32 }

    33 console.log(Prime number > , strPrimeNum); 打印输出质数序列

    34 rl.close;

    35 });

    【代码分析】

    第04~05行定义了验证计算需要的变量,其中变量bFlag可以理解为一个布尔

    型变量,用于保存验证成功的质数,而变量strPrimeNum则用于保存全部验证成功

    的质数序列;第06行开始的关于接受用户控制台输入的代码与前面若干节基本类

    似,在此就不过多阐述了;第16行我们先将整数2(最小的质数)保存到字符串变量strPrimeNum中;第17~32行通过for循环语句来逐次验证从1至用户输入的整数之

    间的全部整数,其中第20~27行通过for循环语句来验证是否满足质数的条件(质

    数只能被1和其自身整除),通过第24行的bFlag变量来进行标记,然后通过第28~

    31行将质数保存在字符串strPrimeNum变量中,最后由第33行使用console.log

    方法进行直接打印输出。

    图1.30是在Ubuntu环境下本例程调试输出的结果。

    图1.30 质数输出

    提示:在实际编程求解过程中,类似布尔型bFlag变量的用法是很常见的,许

    多基础编程语言的算法书中都有论述,感兴趣的读者可以自行参考学习。

    1.21 打印输出杨辉三角

    本节我们来尝试使用Node.js框架方式编程打印输出杨辉三角,所谓杨辉三角

    最本质的特征是,它的两条斜边都是由数字1组成的,而其余的数则是等于它肩上的

    两个数之和。我们选择一个古典的杨辉三角样式供读者了解,如图1.31所示。图1.31 古典杨辉三角样式

    如果通过编程方式打印输出杨辉三角,除了需要了解其实现算法外,格式控制

    也是很重要的环节,否则无法输出有效的三角形形状。

    本例ch01.console-YHTriangle.js主要代码如下:

    01

    02 ch01.console-YHTriangle.js

    03

    04 var i, j, k, strLine;

    05 var readline = require('readline');

    06 rl = readline.createInterface(

    07 process.stdin,08 process.stdout

    09 );

    10 rl.question(line is:, function(iLine) { 请输入杨辉三角行数

    11 输出杨辉三角第一行

    12 strLine = >;

    13 for(i=1; i<=10iLine; i++)14 {

    15 if(i == 5iLine)

    16 {

    17 strLine = strLine + 1;

    18 } else {

    19 strLine = strLine + ;

    20 }

    21 }

    22 console.info(strLine);

    23 输出杨辉三角后续行

    24 strLine = >;

    25 for(j=1; j<=iLine-1; j++)

    26 {

    27 for(k=1; k<5(iLine-j-1); k++)

    28 {

    29 strLine = strLine + ;

    30 }

    31 y = 1;

    32 strLine = strLine + FormatNumber(y);

    33 for(k=1; k<=j; k++)

    34 {

    35 y = y(j-k+1)k;

    36 strLine = strLine + FormatNumber(y);

    37 }

    38 console.info(strLine);

    39 strLine = >;

    40 }

    41 rl.close;

    42 });

    43

    44 FormatNumber方法用于格式化输出杨辉三角

    45 @param y46 @returns {string}

    47 @constructor

    48

    49 function FormatNumber(y) {

    50 var strL = ;

    51 if(y < 10)

    52 {

    53 strL = strL + + y + ;

    54 }

    55 else if((y >= 10) (y < 100))

    56 {

    57 strL = strL + + y + ;

    58 }

    59 else if(y >= 100)

    60 {

    61 strL = strL + + y + ;

    62 }

    63 return strL;

    64 }

    【代码分析】

    该例程首先通过第13~21行打印输出了杨辉三角的第一行,之所以单独打印输

    出第一行主要是为了控制输出格式,然后通过第25~40行依次打印输出了剩余的

    行,打印输出过程中调用了一个用于控制格式的自定义函数FormatNumber,该函

    数通过判断数字位数来调整其间距。该例程可以接受用户的输入,根据用户输入的

    具体行数来打印输出杨辉三角。

    图1.31是一个七行的古典杨辉三角,下面我们在Ubuntu环境下打印输出现代版

    的七行杨辉三角,如图1.32所示。图1.32 打印输出杨辉三角

    提示:杨辉三角,又称帕斯卡三角形,是二项式系数在三角形中的一种几何排

    列。我们之所以习惯称其为杨辉三角是因为它最早出现在我国南宋数学家杨辉1261

    年所著的《详解九章算法》一书里。

    1.22 汉诺塔(Hanoi)问题

    还记得在大学C语言基础课上讲递归算法时的经典汉诺塔(Hanoi)例子吧,本

    节我们通过Node.js框架方式编程来实现。

    汉诺塔(Hanoi)是根据一个古老传说而形成的数学问题,有3根柱子A,B,C,其中A柱上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小,要求按下列规

    则将所有圆盘移至C杆。

    规则一:每次只能移动一个圆盘。

    规则二:大盘不能叠在小盘上面。下面具体通过三个盘子的移动示意图让读者

    对汉诺塔(Hanoi)问题有一个感性的认识,如图1.33所示。图1.33 汉诺塔(Hanoi)示意图

    上图中左上角的图例是初始状态,所有圆盘按照从大到小顺序依次放在A柱上,然后按照汉诺塔(Hanoi)规则依次通过7步的移动将圆盘移动到C柱上,移动过程

    中所有圆盘的摆放顺序均满足从大到小的方式,右下角图例为最终状态。

    其实通过递归算法编程模拟汉诺塔(Hanoi)问题,还是非常容易的,本例

    ch01.console-hanoi.js主要代码如下:

    01

    02 ch01.console-hanoi.js

    03

    04 var iCount = 0; TODO: 定义移动次数

    05 var strMoveStep = ; 保存移动步骤

    06 var readline = require('readline');

    07 var rl = readline.createInterface({

    08 input: process.stdin,09 output: process.stdout

    10 });

    11 rl.question(请输入汉诺塔问题的圆盘数目:\t, function(count) {

    12 print user input

    13 console.log(输入汉诺塔问题的圆盘数目为:\t, count);

    14 hanoi(count, A, B, C);

    15 console.info(移动步骤如下:\t%s, strMoveStep);

    16 console.info(移动次数为:\t%s, iCount);17 rl.close;

    18 });

    19

    20 移动圆盘的方法

    21 @param x

    22 @param y

    23

    24 function move(x, y) {

    25 iCount++;

    26 console.info(%s->%s, x, y);

    27 strMoveStep += x + -> + y + \t;

    28 }

    29

    30 完成汉诺塔问题的递归方法

    31 @param m

    32 @param a

    33 @param b

    34 @param c

    35

    36 function hanoi(m, a, b, c) {

    37 if(m == 1)

    38 {

    39 move(a, c);

    40 }

    41 else

    42 {

    43 hanoi(m-1, a, c, b);

    44 move(a, c);

    45 hanoi(m-1, b, a ,c);

    46 }

    47 }【代码分析】

    该例程的核心部分为第36~47行实现的递归方法hanoi,该方法模拟了根据

    汉诺塔(Hanoi)规则的移动步骤;其中move方法用于保存每一步移动的记录,为了方便最后输出在一行当中,我们将移动步骤保存在字符串变量strMoveStep之

    中,move方法的具体实现见第24~28行;该例程可以接受用户的输入,根据用户

    输入的具体圆盘数目来打印输出移动步骤。

    下面我们在Ubuntu环境下打印输出汉诺塔(Hanoi)问题的移动步骤,如图

    1.34所示。

    图1.34 汉诺塔(Hanoi)问题移动步骤

    提示:现代人根据汉诺塔(Hanoi)问题原理,又衍生出单层、双层汉诺塔

    (Hanoi)问题,四柱、多柱汉诺塔(Hanoi)问题,感兴趣的读者可以自行查阅有

    关资料,做更深一步的学习研究。

    1.23 简单四则运算应用

    在本章最后一节,我们实现一个简单的四则运算应用。在数学中,我们把包含一级运算(加减)和二级运算(乘除)、以及括号运算符(优先级)的运算叫四则

    运算。之所以称为简单四则运算应用,是因为将其简化为仅仅包含两个运算数,且

    不含括号的二元运算,主要目的就是测试一下在Node.js框架下通过编程实现数值

    运算的方法。

    本例ch01.console-calculate.js主要代码如下:

    01

    02 ch01.console-calculate.js

    03

    04 var a, b, sign, summary;

    05 console.info(Calculate start!);

    06

    07 模拟一个控制台输入界面

    08 @type {exports}

    09

    10 var readline = require('readline'); 引入'readline'模块

    11 rl = readline.createInterface(

    12 process.stdin,13 process.stdout

    14 );

    15 rl.setPrompt('Calculate> ');

    16 rl.prompt;

    17 a = Math.round(Math.random 100); 随机生成100以内的整数

    18 b = Math.round(Math.random 100); 随机生成100以内的整数

    19 sign = Math.round(Math.random 3); 随机选取四则运算符

    20 summary = switchSign(a, b, sign);

    21 rl.on('line', function(line) {

    22 if(line.trim == summary) { 判断用户给出的运算结果是否正确

    23 console.info(answer is right!);

    24 } else {

    25 console.info(answer is error! The correct answer is + summary + .);26 }

    27 rl.prompt;

    28 a = Math.round(Math.random 100); 随机生成100以内的整数

    29 b = Math.round(Math.random 100); 随机生成100以内的整数

    30 sign = Math.round(Math.random 3); 随机选取四则运算符

    31 summary = switchSign(a, b, sign);

    32 }).on('close', function {

    33 console.log('Calculate exits!');

    34 process.exit(0);

    35 });

    36

    37 四则运算方法 - switchSign

    38 @param a

    39 @param b

    40 @param sign - 运算符

    41 @returns {}

    42

    43 function switchSign(a, b, sign) {

    44 var c;

    45 switch(sign) {

    46 case 0:

    47 c = a + b;

    48 console.info(a + + + b + =);

    49 break;

    50 case 1:

    51 c = a - b;

    52 console.info(a + - + b + =);

    53 break;

    54 case 2:

    55 c = a b;

    56 console.info(a + + b + =);

    57 break;58 default:

    59 c = a + b;

    60 console.info(a + + + b + =);

    61 break;

    62 }

    63 return c;

    64 }

    【代码分析】

    该例程首先基于第1.18节(模拟一个简单的控制台界面)的内容实现一个带提

    示符(Calculate>)的四则运算控制台界面,然后循环输出系统给出的随机计算表

    达式,由用户一一做出解答。每次做答后系统都会提示用户给出的结果是否正确,并给出提示信息,如果计算结果有误还会给出正确的答案。另外,无论计算正确与

    否都不会终止应用运行,直到用户强行终止这个模拟出来的控制台界面。

    图1.35是在Ubuntu环境下本例程调试输出的结果。

    图1.35 简单四则运算应用

    提示:本例程中用到的Math.random方法属于JavaScript语言范畴,其功能是令系统随机选取大于等于0.0且小于1.0的伪随机double值,感兴趣的读者可以自

    行参考相关文档进行学习。第2章 Node.js模块与包管理

    Node.js框架有一套简单的模块加载系统,在Node.js框架中的文件和模块都是

    一一对应联系的。众所周知,在开发一个复杂的应用级框架的时候,需要把各个功

    能拆分、封装到不同的模块之中,在需要的时候调用该模块。高水平的应用开发不

    会出现一个模块文件有成千上万行的代码,这样的模块文件在可读性、复用性和维

    护性上都是很差的。

    几乎所有的高级编程语言都有自己的模块组织方式,比如Java中的包

    (package)、PHP中的inc文件等。同样的,Node.js框架使用模块和包来组织管

    理,其实现机制参照了CommonJS标准,因此Node.js框架对开发人员来讲是易学易

    懂、使用方便的。

    Node.js框架的模块及包管理从性质及加载方式上可以分为4类内容:核心模

    块、文件模块、文件夹加载和模块缓存。本章将从这几类入手,向读者介绍一些非

    常实用的应用例程。

    本章主要包括以下内容。

    Node.js框架的模块化与包管理机制。

    Node.js框架的核心模块应用。

    Node.js框架的文件模块应用。

    Node.js框架的文件夹加载。

    Node.js框架的模块缓存。2.1 Node.js框架加载核心模块

    Node.js框架中有一些模块是被编译成了二进制的,这些模块一般称为核心模

    块。核心模块定义在Node.js框架源代码文件夹的lib目录下,使用require方法

    进行加载。在Node.js框架中,console模块、URL与QueryString模块、Path与

    File System模块都是核心模块,在第1章已经详细地介绍了console模块,其他模

    块之后也会陆续被介绍到。下面我们通过展示一张结构图,让读者对核心模块有一

    个感性的认识,如图2.1所示。

    图2.1 Node.js框架核心模块示意图

    从图中我们可以看到,最底层的是Google V8 JavaScript引擎,在V8引擎之

    上是基于CC++语言实现的核心模块、并提供向上的接口,在最上层使用

    JavaScript语言对这些接口进行封装、再向外提供给用户使用这些核心模块。

    在Node.js框架应用中,require方法总是会优先加载核心模块。例如,require('http')总是返回编译好的HTTP模块,而不管是否有同名的文件。本例ch02.module-core.js主要代码如下:

    01

    02 ch02.module-core.js

    03

    04 var http = require('http'); 加载核心模块‘http’

    提示:关于Node.js框架总是优先加载核心模块的说法,我们可以这样去理

    解:在Node.js框架安装好后,这些核心模块以编译好的二进制形式作为框架原生

    的组成部分存在,因此require方法即使遇到与模块同名的文件也不予理睬,而

    是直接返回已经编译好的核心模块。

    2.2 Node.js框架加载文件模块

    Node.js框架有一个简易的模块加载系统,在Node.js框架中的文件和模块是一

    一对应的。那么Node.js框架如何加载文件模块呢?下面我们借用官方文档中提供

    的一个示例来阐述加载文件模块的方法。

    这个例子是foo.js文件加载同一目录下的circle.js文件,其功能是通过给定

    的半径来计算圆的周长和面积。

    本例ch02.module-file-foo.js主要代码如下:

    01

    02 ch02.module-file-foo.js

    03

    04 var circle = require('.ch02.module-file-circle.js');

    05 console.info;

    06 var readline = require('readline');

    07 var rl = readline.createInterface({

    08 input: process.stdin,09 output: process.stdout

    10 });

    11 rl.question(Please input radius:\t, function(answer) {

    12 打印用户输出

    13 console.log(The radius is:\t, answer);

    14 console.log( 'The area of a circle of radius ' + answer + ' is ' + circle.area(answer));

    15 console.log( 'The circumference of a circle of radius ' + answer + ' is ' + circle.circumference

    (answer));

    16 console.info;

    17 rl.close;

    18 });

    ch02.module-file-circle.js文件接受用户输入的半径数值,然后调用

    ch02.module-file-circle.js文件模块计算圆的面积和周长。

    本例ch02.module-file-circle.js文件模块主要代码如下:

    01

    02 ch02.module-file-circle.js

    03

    04 var PI = Math.PI;

    05 exports.area = function(r) {

    06 return PI r r;

    07 };

    08 exports.circumference = function(r) {

    09 return 2 PI r;

    10 };

    【代码分析】

    ch02.module-file-circle.js文件模块输出了area和circumference

    两个函数,分别用于计算圆的面积和周长。当文件模块要输出某个对象时,把其加

    到exports这个特殊对象下即可。在这里需要读者注意的是,exports是对module.exports的一个引用,使用exports仅仅是为了用户使用方便。因此,如果

    想输出的是诸如构造函数这样的单个项目,那么就必须使用module.exports。

    关于正确输出构造函数的语法如下:

    语法:module.exports = MyConstructor;

    另外,模块内的本地变量是私有的,因此在本例中,PI这个变量就是

    ch02.module-file-circle.js模块所私有的。

    图2.2是在Ubuntu环境下本例程调试输出的结果。

    图2.2 文件模块调试输出窗口

    提示:使用require方法引用文件模块时,如果按文件名没有查找到,那么

    Node.js框架会添加.js和.json后缀名尝试加载,如果还是没有找到,最后会加

    上.node的后缀名再次尝试加载。其中,.js会被解析为JavaScript纯文本文

    件,.json会被解析为JSON格式的纯文本文件,.node则是通过CC++进行编写的插

    件,最终会被解析为编译后的插件模块,由dlopen方法(Linux CC++编程范

    畴)进行加载。

    2.3 从node_modules文件夹中加载

    如果require方法中的模块名不是一个本地模块,也没有以‘’、‘..’、或是‘.’这样的相对路径开头,那么Node.js框架会从当前

    模块的父目录开始,尝试在node_modules文件夹里加载相应模块。如果仍旧没有找

    到相应模块,则再移动到上一级父目录,直到到达顶层目录位置。

    我们来举个例子,如果位于homekingwebstorm-

    jsprojectschapter02foo.js的文件调用了require('circle.js'),因为其

    没有‘’、‘..’、或是‘.’这样的相对路径开头,那么Node.js框架查找的

    位置依次为:

    homekingwebstorm-jsprojectschapter02node_modulesfoo ......


您现在查看是摘要介绍页, 详见PDF附件(44878KB,584页)