购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.1 Node.js基础

本节将讲解Node.js简介、发展历史、组织架构、特点以及具体应用等方面的内容。

1.1.1 Node.js简介

Node.js是基于Google Chrome浏览器内置的V8引擎所开发的JavaScript运行时环境。它充分利用了V8引擎的强大性能,借鉴了其很多的前沿技术(例如:GC机制、事件驱动、非阻塞的I/O模型,等等),保证了Node.js的轻量与高效,进而受到了众多开发者的追捧。

Node.js最显著的特点就是能够运行在服务器端(区别于其他脚本语言),以及良好的多平台兼容性(支持Windows、Linux、Mac OS X、SunOS和FreeBSD等多种系统平台),使其成为最重要的脚本程序设计语言。

我们都知道,JavaScript脚本语言需要在浏览器环境下才可以解释执行。而Node.js是服务器端的脚本语言,可以直接在后端进行解释执行。下面就是最基本的Node.js命令执行方法。

node filename.js    //node命令直接解释执行filename.js脚本文件,得到结果

由于Chrome V8引擎执行JavaScript脚本的速度非常快,因此Node.js所开发出来的应用程序性能非常好。Node.js已经成为全栈开发的首选语言之一,并且从它衍生出众多出色的全栈开发框架。Node.js在全球已经被众多公司使用,包括创业公司Voxer、Uber,以及知名公司沃尔玛、微软等。它们每天通过Node.js处理的请求数以亿计,可以说对于要求苛刻的服务器系统来说,Node.js也可以轻松胜任。

Node.js还包括一个完善的社区。在Node.js的官方网站https://nodejs.org/可以找到大量的帮助文档和示例程序,并且Node.js还有一个强大的npm包管理器。由于其强大的服务端功能,越来越多的人参与到本项目中来,可用的第三方模块和扩展增长迅猛,而且质量也在不断提升,Node已是全球较大的开源库生态系统之一。

提示: Node.js并不是一个JavaScript应用,而是一个JavaScript的运行时环境,其底层由C++语言编写而成。

1.1.2 Node.js的发展历史

任何语言或框架都不是一天形成的,而是经过漫长的测试、发布、再测试、再发布的迭代过程,本节将重点介绍一下Node.js的发展历史。

Node.js的创始人就是大名鼎鼎的Ryan Dahl。Ryan Dahl其实是学数学的,在2008年年末,一个偶然的机会让他知道了Google推出的全新的Chrome浏览器及其V8引擎。而当他了解到,Chrome V8是一个为了实现更快的Web体验而专门制作的JavaScript引擎时,非常希望能找到一种语言能够提供先进的推送功能,并集成到自己的网站中去,从而避免采用传统的不断轮询拉取数据的访问方式。

Ryan Dahl对C/C++和系统调用非常熟悉,他使用系统调用(用C)实现消息推送功能。如果只使用非阻塞式Socket,每个连接的开销都会非常小。在小规模测试中,它能同时处理几千个闲置连接,并可以实现相当大的吞吐量。但是,他并不想使用C,他希望能采用另外一种漂亮灵活的动态语言。最初他也想使用Ruby来写Node.js,但是发现Ruby虚拟机的性能不能满足要求,后来便尝试采用V8引擎,所以选择了C++语言。

2009年2月,Ryan Dahl首次在自己的博客上宣布准备基于V8创建一个轻量级的Web服务器并提供一套库。2009年5月,他正式在GitHub上发布最初版本的部分Node.js包。随后几个月里,有人开始使用Node.js开发应用。实践证明,JavaScript与非阻塞Socket配合得相当完美,只需要简单的几行JavaScript代码,就可以构建出非常复杂的非阻塞服务器。到了2010年年底,Node.js获得云计算服务商Joyent的资助。创始人Ryan Dahl加入Joyent,全职负责Node.js的发展。从此以后Node.js迅猛发展,并成为一种流行的开发语言。

在官方网站上,Node.js的版本号是从0.1.14开始的,每个发布版本对应不同的V8引擎版本和npm包管理器版本。截至笔者写作时,最新的LTS(Long-Term Support,长期支持)版本为V18.17.1。当然,这期间Node.js发生了很曲折的故事,感兴趣的读者可以自行去了解一下。

总结一下,Node.js的发展大致可以分为如下4个阶段。

1.发展初期

创始人Ryan Dahl带着他的团队开发出以Web为中心的Web.js,此时的一切都非常混乱,API也大多处于试验阶段。

2.快速发展时期

Node.js的核心用户Isaac Z. Schlueter开发出了奠定Node.js如今地位的重要工具—npm包管理工具。同时,这也是Schlueter未来成为Ryan接班人的重要条件。之后Connect、Express、Socket.io等库的出现,吸引了一大波爱好者加入Node.js开发者阵营。CoffeeScript的出现更是让不少Ruby和Python开发者找到了学习的理由。期间,以Node.js作为运行环境的CLI工具涌现出来,其中不乏用于加速前端开发的优秀工具,如Babel、Less、Sass、UglifyJS、Browserify、Grunt、Gulp等。在这个阶段,Node.js的发展势如破竹。

3.不稳定时期

经过了一大批一线工程师的探索实践后,Node.js开始进入时代的更迭期,新模式代替旧模式,新技术代替旧技术,新实践代替旧实践。ECMAScript 6(ECMAScript 2015)也开始出现在Node.js世界中。ECMAScript 6的发展越来越明显,V8也对ECMAScript 6中的部分特性实现了支持,如Generator等。

4.稳步发展时期

随着ECMAScript 6的发展和最终定稿,出现了大量利用ECMAScript 6特性开发的新模块,如原Express核心团队开发的Koa。Node.js之父Ryan Dahl退出Node.js的核心开发,转做其他的研究项目。Ryan Dahl的接任者Schlueter负责将Node.js一直开发下去并不断进行完善。

1.1.3 Node.js组织架构

前面介绍了Node.js是一个完整的JavaScript开发环境,并且是基于Google的Chrome V8引擎进行代码解释的。它在设计之初就已经被定位用来解决传统Web开发语言所遇到的诸多问题,所以Node.js有很多其他开发语言所不具备的优点。下面主要介绍Node.js的组织架构,如图1.1所示。

图1.1 Node.js系统架构图

从图1.1中可以看到,只有最顶层的Node标准库(Node standard library)部分是用JavaScript语言编写的,其余的底层均是用C/C++语言编写的。

继续分析图1.1中描述的Node.js组织架构,关于Node.js的结构大致可以分为以下3个层次。

1.Node.js标准库

这一层由JavaScript编写,是在使用过程中能直接调用的API。它在Node.js源代码中的lib目录下可以看到,具体包括http、net、stream、fs、buffer、events等模块。

2.Node bindings

这一层是JavaScript与底层C/C++能够沟通的关键,前者通过bindings调用后者,相互交换数据。

3.Node基础构件

这一层是支撑Node.js运行的基础构件,使用C/C++语言编写,具体包括以下主要模块。

· V8:Google推出的JavaScript VM,也是Node.js为什么使用JavaScript的关键,它为JavaScript提供了在非浏览器端运行的环境,它的高性能是Node.js之所以高效的原因之一。

· libuv:为Node.js提供了跨平台、线程池、事件池、异步I/O等能力,是Node.js如此强大的关键。

· C-ares:提供了异步处理DNS相关的能力。

· http_parser、OpenSSL、zlib等:提供了包括HTTP解析、OpenSSL、数据压缩等功能。

1.1.4 Node.js的特点

Node.js的强大体现在很多方面,如事件驱动、异步处理、非阻塞I/O等。这里将介绍Node.js具备的不同于其他框架的特点,包括事件驱动、异步非阻塞I/O、高性能、单线程等。

1.事件驱动

在某些传统的网络编程语言中,都会用到回调函数。比如:当Socket资源达到某种状态时,注册的回调函数就会执行。在Node.js的设计思想中,是以事件驱动为核心的,它提供的绝大多数API都是基于事件的、异步的风格。以net模块为例,其中的net.Socket对象就有connect、data、end、timeout、drain、error、close等事件。使用Node.js的开发人员,需要根据自己的业务逻辑注册相应的回调函数。这些回调函数都是异步执行的。这意味着虽然在代码结构中这些函数看起来是依次注册的,但是它们并不依赖于自身出现的顺序,而是等待相应的事件触发。

事件驱动的优势在于充分利用了系统资源,执行代码无须阻塞等待某种操作完成,有限的资源可以用于其他的任务。此类设计非常适合后端的网络服务编程,Node.js的目标也在于此。在服务器开发中,并发的请求处理是一个大问题,阻塞式的函数会导致资源浪费和时间延迟。通过事件注册、异步函数,开发人员可以提高资源的利用率,性能也会得到改善。

2.异步非阻塞I/O

从Node.js提供的支持模块中可以看到,包括文件操作在内的许多函数都是异步执行的,这和传统语言存在区别。为了方便服务器开发,Node.js的网络模块特别多,包括http、dsn、net、udp、https、tls等。开发人员可以在此基础上快速构建Web服务器应用。一个异步I/O的大致流程如图1.2所示。

图1.2 异步I/O的流程

异步I/O流程主要包括以下过程:

(1)发起I/O调用:

① 用户通过JavaScript代码调用Node核心模块,将参数和回调函数传入核心模块。

② Node核心模块会将传入的参数和回调函数封装成一个请求对象。

③ 将这个请求对象推入I/O线程池等待执行。

④ JavaScript发起的异步调用结束,JavaScript线程继续执行后续操作。

(2)执行回调:

① I/O操作完成后会将结果存储到请求对象的result属性上,并发出操作完成的通知。

② 每次事件循环时会检查是否有完成的I/O操作,如果有,就将请求对象加入I/O观察者队列中,之后当作事件处理。

③ 处理I/O观察者事件时,会取出之前封装在请求对象中的回调函数,执行这个回调函数,并将result当作参数,以实现JavaScript回调的目的。

Node.js的网络编程非常方便,提供的模块(在这里是HTTP)开放了容易上手的API接口,短短几行代码就可以构建服务器。

3.性能出众

创始人Ryan Dahl在设计的时候就考虑了性能方面的问题,因此选择了C++和V8,而不是Ruby或者其他的虚拟机。Node.js在设计上以单进程、单线程模式运行。事件驱动机制是Node.js通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文切换。这意味着面对大规模的HTTP请求,Node.js是凭借事件驱动来完成的。从大量的测试结果分析来看,Node.js的处理性能非常出色,在QPS(每秒查询率)达到16 700次时,内存仅占用30MB(测试环境:RHEL 5.2、CPU 2.2GHz、内存4GB)。

4.单线程

Node.js和大名鼎鼎的Nginx一样,都是以单线程为基础的。这正是Node.js保持轻量级和高性能的关键,也是Ryan Dahl设计Node.js的初衷。这里的单线程是指主线程为“单线程”,所有阻塞的部分交给一个线程池处理,然后这个主线程通过一个队列跟线程池协作。我们写的JavaScript代码部分不用关心线程问题,代码也主要由一堆回调函数构成,然后主线程在循环过程中适时调用这些代码。

单线程除了保证Node.js高性能之外,还保证了绝对的线程安全,使开发者不用担心因为同一变量同时被多个线程读写,而造成的程序崩溃。

1.1.5 Node.js应用场景

Node.js可以应用到很多方面,可以说从Node.js开始,开发者就可以使用JavaScript来开发服务器端的程序了。Node.js为前端开发者提供了便利,并在各大网站中承担重要角色,成为开发高并发大型网络应用的关键技术。Web站点早已不局限于内容的呈现,很多交互型和协作型环境也逐渐被搬到了网站上,而且这种需求还在不断增长。这就是所谓的数据密集型实时(data-intensive real-time)应用程序,例如在线协作的白板、多人在线游戏等。这种Web应用程序需要一个能够实时响应大量并发用户请求的平台来支撑它们,而这也正是Node.js擅长的领域。此外,Node.js的跨平台特性也是开发人员选择使用Node.js语言进行开发的另一大原因。

Node.js的主要应用场景如下:

· JSON APIs:构建一个Rest/JSON API服务,Node.js可以充分发挥其非阻塞I/O模型以及JavaScript对JSON的功能支持(如JSON.stringfy函数)。

· 单页面、多Ajax请求应用:如Gmail,前端有大量的异步请求,需要服务后端有极高的响应速度。

· 基于Node.js开发UNIX命令行工具:Node.js可以大量生产子进程,并以流的方式输出,这使得它非常适合用作UNIX命令行工具。

· 流式数据:传统的Web应用通常会将HTTP请求和响应看作原子事件,而Node.js会充分利用流式数据的这个特点,构建非常酷的应用,如实时文件上传系统Transloadit。

· 准实时应用系统:如聊天系统、微博系统,但JavaScript是有垃圾回收(GC)机制的,这就意味着系统的响应时间是不平滑的(垃圾回收会导致系统在这一时刻停止工作)。如果想要构建硬实时应用系统,Erlang是一个不错的选择。

例如,实时互动交互比较多的社交网站,像Twitter这样的公司,它必须接收tweets并将其写入数据库。实际上,几乎每秒就有数千条tweets达到,数据库不可能及时处理高峰时段所需的写入数量。Node.js成为解决这个问题的重要一环。Node.js能处理数万条入站tweets。它能快速而又轻松地将它们写入一个内存排队机制(例如memcached),而另一个单独进程可以在那里将它们写入数据库。Node.js能处理每个连接而不会阻塞通道,从而能够捕获尽可能多的tweets。

虽然看起来Node.js可以做很多事情,并且拥有很高的性能,但是Node.js并不是万能的,有一些类型的应用Node.js处理起来可能会比较吃力。例如,CPU密集型的应用、模板渲染、压缩/解压缩、加/解密等操作都是Node.js的软肋。

1.1.6 Node.js在国内的发展

在Node.js初期发展的时候,国内就有大量的开发者开始持续关注了。随着Node.js的不断成熟,很多国内的公司都开始采用这一新技术。Node.js开发者在国内的数量不断增加,并涌现出很多组织和机构来自发地进行推广和技术分享。

国内的各大视频培训网站上都有Node.js开发的培训教程,各大门户网站也都或多或少地采用了Node.js的开发技术,比如淘宝、网易、百度等有很多项目就运行在Node.js之上。阿里云是这方面比较靠前的公司,它们的云平台率先支持Node.js的开发。淘宝也为Node.js搭建了国内的NPM镜像网站,方便国内的开发者下载各种开发包。

以下是关于Node.js中文资源的汇总清单:

(1)Node.js官方网站:该网站是Node.js在国内的官方网站,里面有Node.js最新版本的下载资源和丰富的文档资料,是Node.js开发爱好者不容错过的网站。网址为https://nodejs.org/en/。

(2)CNode社区:该社区由一批热爱Node.js技术的工程师发起,已经吸引了很多互联网公司的专业技术人员加入,是目前国内非常具有影响力的Node.js开源技术社区。它致力于Node.js的技术研究,拥有论坛,并定期组织一些技术交流活动。网址为https://cnodejs.org。

(3)Node.js中文网:该网站是一个专业的Node.js中文知识分享社区,致力于普及Node.js知识,分享Node.js研究成果,努力推进Node.js在中国的应用和发展。网站中有大量的技术博客和文章,各个级别的开发者都能找到适合自己学习的资料。网址为https://www.nodejs.cn/。

(4)淘宝NPM镜像:是一个完整npmjs.org镜像,可以用此代替官方版本,同步频率为每10分钟一次,以保证尽量与官方服务同步。网址为https://npm.taobao.org/。

(5)Node.js:这也是一个学习Node.js和前端开发技术非常好的网站,每天都有大量原创文章发布,并且技术问题可以很快被回答。当然,如果你愿意为其他人解答技术问题,或者进行技术分享,也是非常受欢迎的。网址为http://cnodejs.org/。

每年的JavaScript中国开发者大会和各种Node.js分享沙龙,都是很好的学习Node.js开发技术和交流的机会。一个开发者要时刻保持谦虚的心态,并不断学习最新的技术,这对开发者来说是一种基本能力和素养。 xghW3iskZgMMpIRNsq43khWY+yd+8SpGqYDyu8+39D9W0Rtb5JkuPIyvtLouKarV

点击中间区域
呼出菜单
上一章
目录
下一章
×