2.1 JavaSc ript的运行环境Node.js
2.1.1 什么是Node.js
Node.js这个名字很容易让人以为是一个JavaScript的应用或类库。实际上,Node.js是一个JavaScript的运行环境,主要采用C++语言编写而成。
要了解Node.js,首先要了解什么是JavaScript引擎。JavaScript是一门高级语言,计算机并不能直接执行,所以需要使用所谓的引擎来将其转换成计算机能理解的机器语言。最初,JavaScript主要运行在浏览器里,浏览器中的JavaScript引擎负责解析和执行网页中的JavaScript代码,并提供代码执行的运行环境,例如内存管理(内存分配,垃圾回收)、即时编译(Just-in-time Compilation)、类型系统(Type System)等服务。
C#和JavaScript的运行环境对比,如表2-1所示。
表2-1 C#和JavaScript的运行环境比较
如果能把JavaScript引擎从浏览器中独立出来,那么JavaScript代码就可以被移植到浏览器以外的环境中执行,和其他高级编程语言一样做网页交互以外的事情,从而大大拓宽了JavaScript的应用范围。
2008年,Google公司为Chrome浏览器开发了开源JavaScript引擎V8。Node.js的诞生可以说很大程度上归功于V8引擎的出现。当时其他JavaScript引擎对JavaScript代码进行解释执行,性能较差;而V8使用即时编译,在代码执行前将JavaScript编译成二进制机器码再执行,极大地改善了JavaScript程序的性能,使得JavaScript程序在V8引擎下的运行速度可以媲美二进制程序。
除了能够大幅提升JavaScript性能,V8引擎也可以作为独立的模块,由开发者在自己的C++程序中“嵌入”V8引擎,从而高效地编译JavaScript。
2009年,Ryan Dahl创建了基于V8引擎的Node.js项目(后来得到Joyent公司的资助)。Node.js是一个开源的、跨平台的JavaScript运行环境,最初发布在Linux平台上,直到2011年7月,在微软的支持下才发布了Windows版本。它对V8引擎进行了封装,并提供很多系统级的接口调用,如文件操作、网络编程等,可以用JavaScript编写响应速度快、易于扩展的网络应用。
Ryan Dahl创造Node.js的目的是为了实现高性能的Web服务器。在传统服务器软件开发中,并发的请求处理一直是个大问题。传统服务器模型通常为每一个请求生成一个新线程或新进程,一方面服务器创建新线程/新进程会造成延时,另外一方面,新线程/新进程会消耗额外的内存,浪费资源。在这种传统模型中,如果应用程序的某个任务很耗时,涉及到大量I/O操作(比如访问文件),对应的线程就处于一种不占用CPU,而只是等待响应的状态,直到数据传输完成。但由于等待期间该线程/进程依然占用着资源,当大量并发请求到达时,就会产生阻塞,造成服务器瓶颈。
Node.js以事件驱动为核心,使用非阻塞I/O模型,它为每个连接发出(emit)一个事件(event),放进事件队列当中,而不是为每个连接生成一个新的线程/进程。理论上,只要有用户请求连接,Node.js都可以进行响应。同时,该I/O模型提供的绝大多数应用编程接口都是基于事件的、异步的风格。开发人员根据自己的业务逻辑需要在相应的事件上注册回调函数,这些回调函数在相应事件触发后被调用。例如,当应用程序发生一个I/O操作(比如访问文件)时,Node.js的主线程可以继续执行,而无需等待这个操作完成;等到这个I/O操作完成,相应事件被触发的,回调函数被再执行。这使得Node.js在相对较低的系统资源消耗下具有高性能与出众的高并发能力。
JavaScript是Node.js的天然载体语言,因为它允许使用匿名函数和闭包,非常适合事件驱动和异步编程。并且JavaScript作为一门编程语言自身不带I/O功能(一般的编程语言都带一个I/O模块,很不幸的是这个模块通常是同步的,而JavaScript最初是在浏览器内运行,浏览器负责I/O,所以JavaScript没有这个历史包袱)。
Node.js自诞生以来发展迅速,社区活跃,吸引全世界开发者为其贡献了大量的工具、模块和框架。很多企业也逐渐开始采用Node.js开发项目。
本书虽然不是介绍如何利用Node.js开发高性能Web应用的,但是示例所需的很多工具和框架依赖于Node.js的JavaScript运行环境,所以需要安装Node.js。
2.1.2 Node.js的版本发展
初次接触Node.js的读者,可能会对Node.js的版本产生困惑。你可能看到过v0.8.x、v0.10.x、v0.11.x、v0.12.x等版本,然后版本号突然变成4.x.x(本书编写时最新版本号是6.8.1),这和Node.js的发展历史有很大的关系。
Ryan Dahl创建Node.js时,采用的是和Linux内核相同的奇偶版本模式,即版本由3个整数组成,格式为“A.B.C”, A代表主版本号,B代表次版本号,C代表较小的末版本号。只有在内核发生很大变化时,A才变化。C代表一些缺陷修复、安全更新、新特性和驱动的次数。而通过数字B来判断产品是否稳定,偶数的B代表稳定版,奇数的B代表不稳定的开发版。
2010年,Joyent公司雇用了Ryan Dahl并让其专职负责Node.js的发展,在此同时,还得到了Node的品牌使用权。Joyent的Node.js继续使用奇偶版本模式,比如v0.8.x、v0.10.x、v0.11.x、v0.12.x。
2012年,Ryan Dahl离开了Node.js的项目负责岗位并淡出了公众视野。Ryan Dahl离开后,Node.js开源社区的贡献者和Joyent发布的更新数量都在不断缩减。
2014年12月,由于对Joyent公司垄断Node.js项目以及该项目进展缓慢的不满,一部分核心开发者离开了Node.js,创造了io.js项目。这是一个更开放、更新更频繁的Node.js版本。io.js的版本策略是语义化版本(Semantic Versioning),使用3个整数表示向后兼容的程度,格式为MAJOR.MINOR.PATCH:
• MAJOR(主要)。此位版本号表示此版本号和前一个版本号在API上不兼容,如3.0.0的API可能不兼容2.0.0的请求。
• MINOR(次要)。此位版本号表示新添加了一个功能,且保持旧功能完全向后兼容。
• PATCH(补丁)。此位版本号表示修复了以前功能的Bug,且完全向后兼容。
2015年2月,Joyent公司宣布放弃对Node.js项目的控制,将其转交给新成立的开放性质的Node.js基金会。
2015年9月,io.js项目宣布回归Node.js。Joyent的Node.js v0.12.7和io.js的v3.3.1合并成新的Node v4.0,这是为了防止与后续Joyent的Node.js 0.x.x维护计划和任何现有的io.js版本发生冲突。这次合并之后,整个项目采用语义化版本编号策略。所以4.0.0是重生后的Node.js真正的“1.0”版本。
注意,如果读者使用的是Visual Studio 2015,安装时可能选装Joyent Node.js,如图2-1所示,但是它的版本是v0.12.2。所以本书建议采用从官网下载安装包的方式安装Node.js。
图2-1 Visual Studio 2015安装界面
2.1.3 安装Node.js
Node.js可以在主流操作系统上运行,包括Windows、Linux和Mac OS。Node.js安装包及源码下载地址为https://nodejs.org/en/download/,如图2-2所示。
图2-2 Node.js下载页面
用户可以根据不同操作系统选择所需要的Node.js安装包。本书示例基于Windows 10操作系统,采用Node.js v4.6.0 LTS(长期支持版本)的64位Windows安装包(.msi)来安装Node.js,步骤如下:
(1)双击下载后的安装包node-v4.6.0-x64.msi,出现欢迎界面,单击Next按钮。
(2)勾选接受最终用户许可协议选项,单击Next按钮,如图2-3所示。
图2-3 Node.js用户许可协议
(3)使用默认安装目录和默认安装方式安装Node.js。安装完毕后单击Finish按钮退出安装向导,如图2-4所示。
图2-4 Node.js安装完成
打开命令控制台,运行以下命令检查当前Node.js的版本:
C:\>node --version v4.6.0
为了验证Node.js能否正常工作,可以直接输入node,按回车键。
C:\>node >
如果Node.js成功安装,此时就进入了Node.js的命令行模式,可以直接输入JavaScript命令,按回车键执行。例如,执行命令console.log('Hello World! '):
C:\>node >console.log('Hello World') Hello World! Undefined
采用以下两种方法可以退出Node.js的命令行模式:
• 按两次快捷键Ctrl+C。
• 输入.exit,按回车键。