前言
作为后端JavaScript的运行平台,Node保留了前端浏览器JavaScript中那些熟悉的接口,没有改写语言本身的任何特性,依旧基于作用域和原型链,区别在于它将前端中广泛运用的思想迁移到了服务器端。下面我们来看看Node相较其他语言的一些特点。
第一章node简介
第二章模块机制
经历了长长的后天努力过程,JavaScript不断被类聚和抽象、以更好地组织业务逻辑。从另一个角度而言,它也道出了JavaScript先天就缺乏的一项功能:模块。
在其他高级语言中,Java有类文件,Python有import机制,Ruby有require,PHP有include和require。而JavaScript通过
3.异步I\O
与Node的事件驱动、,异步IO设计理念比较相近的一个知名产品为Nginx.Nginx采用纯C编写,性能表现非常优异。它们的区别在于,Nginx具备面向客户端管理连接的强大能力,但是它的背后依然受限于各种同步方式的编程语言。但Nodc却是全方位的,既可以作为服务器端去处理客户端带来的大量并发请求,也能作为客户端向网络中的各个应用进行并发请求。
web的含义是网,Node的表现就如它的名字一样,是网络中灵活的一个节点。
4.异步编程
在开始异步编程之前,先得知晓JavaScript现今的回调函数和深层嵌套的来龙去脉。在JavaScript中,函数( function )作为一等公民,使用上非常自由,无论调用它,或者作为参数,或者作为返回值均可。函数的灵活性是JavaScript比较吸引人的地方之一,它与古老的Lisp语言颇具渊源。JavaScript在诞生之前,Brendan Eich借鉴了Scheme语言( Scheme作为Lisp的派生),吸收了函数式编程的精华,将函数作为一等公民便是典型案例。
鉴于函数式编程在近年来重新火热,而前端类图书中较少述及这部分知识,这里稍作补充,因为它是JavaScript异步编程的基础。
第5章内存控制
也许读者会好奇为何会有这样一章存在于本书中,因为在过去很长一段时间内,JavaScript开发者很少在开发过程中遇到需要对内存精确控制的场景,也缺乏控制的手段。说到内存泄漏,大家首先想起的也只是早期版本的IE中JavaScript与DOM交互时发生的问题。如果页面里的内存占用过多,基本等不到进行代码回收,用户已经不耐烦地刷新了当前页面。
随着Node的发展,JavaScript已经实现了CommonJS的生态圈大一统的梦想,JavaScript的应用场景早已不再局限在浏览器中。本章将暂时抛开那些短时间执行的场景,比如网页应用、命令行工具等,这类场景由于运行时间短,且运行在用户的机器上,即使内存使用过多或内存泄漏,也只会影响到终端用户。由于运行时间短,随着进程的退出,内存会释放,几乎没有内存管理的必要。但随着Node在服务器端的广泛应用,其他语言里存在着的问题在JavaScript中也暴露出来了。
基于无阻塞、事件驱动建立的Node服务,具有内存消耗低的优点,非常适合处理海量的网络请求。在海量请求的前提下,开发者就需要考虑一些平常不会形成影响的问题。本书写到这里算是正式迈进服务器端编程的领域了,内存控制正是在海量请求和长时间运行的前提下进行探讨的。在服务器端,资源向来就寸土寸金,要为海量用户服务,就得使一切资源都要高效循环利用。在第3章中,差不多已介绍完Node是如何利用CPU和IO这两个服务器资源,而本章将介绍在Node中如何合理高效地使用内存。
第6章理解Buffer
与第5章介绍的内容一样,本章讲述的也是前端JavaScript开发者不曾涉及的内容。文件和网络IO对于前端开发者而言都是不曾有的应用场景,因为前端只需做一些简单的字符串操作或DOM操作基本就能满足业务需求,在ECMAScript规范中,也没有对这些方面做任何的定义,只有CommonJS中有部分二进制的定义。由于应用场景不同,在Node中,应用需要处理网络协议、操作数据库、处理图片、接收上传文件等,在网络流和文件的操作中,还要处理大量二进制数据,JavaScript自有的字符串远远不能满足这些需求,于是Buffer对象应运而生。
第7章网络编程
Node是一个面向网络而生的平台,它具有事件驱动、无阻塞、单线程等特性,具备良好的可伸缩性,使得它十分轻量,适合在分布式网络中扮演各种各样的角色。同时Node提供的API十分贴合网络,适合用它基础的API构建灵活的网络服务。从本章起,我将介绍Node在网络服务器方面的具体能力。
利用Node可以十分方便地搭建网络服务器。在Web领域,大多数的编程语言需要专门的Web服务器作为容器,如ASP、http://ASP.NET需要IIS作为服务器,PHP需要搭载Apache或Nginx环境等,JSP需要Tomcat服务器等。但对于Node而言,只需要几行代码即可构建服务器,无需额外的容器。
Node提供了net、dgram、http、https这4个模块,分别用于处理TCP 、UDP、HTTP、HTTPS,适用于服务器端和客户端。
第8章构建web应用
为了胜任Web应用的开发工作,各种语言、模式、框架层出不穷。单从框架而言,在后端数得出来大名的就有Structs、Codelgniter、Rails、Django、web.py等,在前端也有知名的BackBone,Knockout. js 、AngularJS、Meteor等。在Node中,有Connect中间件,也有Express这样的MVC框架。值得注意的是Meteor框架,它在后端是Node,在前端是JavaScript,它是一个融合了前后端JavaScript的框架。
由于前后端采用的语言都是JavaScript,在跨越HTTP进行沟通时,会有一些额外的好处。无须切换语言环境,部分知识不会因为语言环境的切换而丢失,上下文一致性较好。数据(因为JSON)可以很好地实现跨前后端直接使用。
一些业务(如模板渲染)可以很自由地轻量地选择是在前端还是在后端进行,因为编程语言相同,所以切换代价小。
第9章玩转进程
Node在选型时决定在V8引擎之上构建,也就意味着它的模型与浏览器类似。我们的JavaScript将会运行在单个进程的单个线程上。它带来的好处是:程序状态是单一的,在没有多线程的情况下没有锁、线程同步问题,操作系统在调度时也因为较少上下文的切换,可以很好地提高CPU的使用率。
但是单进程单线程并非完美的结构,如今CPU基本均是多核的,真正的服务器(非VPS)往往还有多个CPU。一个Node进程只能利用一个核,这将抛出Node实际应用的第一个问题:如何充分利用多核CPU服务器?
另外,由于Node执行在单线程上,一旦单线程上抛出的异常没有被捕获,将会引起整个进程的崩溃。这给Node的实际应用抛出了第二个问题:如何保证进程的健壮性和稳定性?
在这两个问题中,前者只是利用率不足的问题,后者对于实际产品化带来一定的顾虑。本章关于进程的介绍和讨论将会解决掉这两个问题。
从严格的意义上而言,Node并非真正的单线程架构,在第3章中我们有叙述过Node自身还有一定的I/O线程存在,这些IO线程由底层libuv处理,这部分线程对于JavaScript开发者而言是透明的,只在C++扩展开发时才会关注到。JavaScript代码永远运行在V8上,是单线程的。本章将围绕JavaScript部分展开,所以屏蔽底层细节的讨论。
第10章测试
在使用Node进行实际的项目开发之前,我内心也曾十分忐忑。尽管JavaScript历史悠久,但相较成熟的后端语言而言,Node尚且算是新晋同学。甚至对于前端,因为各种各样的原因,JavaScript的测试都十分少。Node编写的在线产品,在成千上万用户面前能否具备良好的质量保证,我是心存疑问的。
从最早写出的代码让自己睡不着觉,无法精确定位bug到底位于一堆程序里的哪个位置,到后来很踏实地面对自己产出的代码,对自己代码的了解如手心纹路那么清晰明了。从面对问题时的被动到主动,测试在这个演变过程中起到了至关重要的作用。
测试的意义在于,在用户消费产出的代码之前,开发者首先消费它,给予其重要的质量保证。这里值得提醒的是,JavaScript开发者需要转变观念,正视自己的代码,对自己产出的代码负责。为自己的代码写测试用例则是一种行之有效的方法,它能够让开发者明确掌握到代码的行为和性能等。
测试包含单元测试、性能测试、安全测试和功能测试等几个方面,本章将从Node实践的角度来介绍单元测试和性能测试。
第11章产品化
Node相对于大多数Web技术还算是年轻的,这意味着没有现成和成熟的框架或应用系统可以直接上手使用,商业化还处于萌芽状态。反过来,这也能让开发者接触到较多的底层细节,如HTTP协议、进程模型、服务模型等,这些底层原理与其他现有技术并无实质性的差别。对于Node开发者而言,很多其他语言走过的路需要开发者带着Node特性重新去践行一遍。这并不是坏事,Node更接近底层使得开发者对于具体细节的可控度非常高。
目前,在国内大多数人都将Node以实验性质的方式来使用,国外已经有知名的项目将Node应用在实际的生产环境中,如eBay的数据中间层、Linkedin移动应用的服务器端等。本章将详细介绍将Node产品化过程中需要注重的一些细节,这些细节其实是具备普适性的,并非Node所独有。鉴于部分Node开发者可能从前端转来,为了完善Node生态的介绍,所以添加了此章。尽管因为熟悉JavaScript,可以较好地上手Node,但是事实上从演示原型到产品还有较长的缝隙需要去填补。
在实际的产品中,需要很多非编码相关的工作以保证项目的进展和产品的正常运行等,这些细节包括工程化、架构、容灾备份、部署和运维等。只有这些任务在持续性进行,才表明项目是活着的。