在大家的印象中,相当长一段时间里,JavaScript是一门脚本语言,一般不能成为某个项目的担纲主角,作用只是在浏览器里帮忙校验校验输入是不是正确,响应一下鼠标、键盘事件,或者让某个HTML元素动起来,搞点特效等等,相当于在剧组中帮忙递递毛巾,打打开水。
后来,AJAX这种数据交互模式的出现,催生了Web2.0的繁荣,让Web页面也能实现像桌面程序一样的效果,用户体验大大提升,但是,它想发挥价值,还必须和另外一个主角(浏览器)一起出场,如果和浏览器的关系搞得不好(不兼容),那么,后果会是非常糟糕的。这时候的JavaScript至少可以认为可以跑跑龙套,偶尔也当一下配角。
而NodeJS的出现,则让JavaScript重新焕发了生机,让它可以离开浏览器,离开Web前端,来到了广阔的网络服务器的新天地,可以在Windows,Linux,Mac OS上运行,成为业务的绝对主角,再也不用低声下气地跟别人谈兼容性,而为它搭台的是大名鼎鼎的Google V8引擎,于是各种好戏轮番上演,精彩不断。
NodeJS是什么,它的历史来源,如何安装,如何测试....已经有很多人谈论了,本文想从业务架构的角度来谈谈NodeJS的特点,这样,当你拿到一个具体的业务的时候, 就知道如何优雅地实现这些业务逻辑,看看NodeJS是否适合你的业务诉求。
特点1:异步I/O,事件驱动模式
我们通过一个故事来感知一下异步业务流程。光明小区的王大姐和李阿姨在“玉湖”网上生鲜超市预订了几只大闸蟹,收到的提示消信息是:今天早上10:30送到光明小区门口。王大姐和李阿姨10:20就来到了小区门口,但是到了10:35,玉湖生鲜超市的送货小哥还没有送到,请问:王大姐和李阿姨可以怎么做?
同步模式:一直在小区门口等,等到11:00终于等到送货的小哥,然后拿着大闸蟹回家做午饭去。
异步模式:两位估计一时半会儿大闸蟹是不会送到了,于是跟守门的张大爷说:“我们先去那边跳一会儿广场舞,如果你看到‘玉湖’生鲜超市的车到了,给我们打个电话,谢谢。”于是两位就高兴地去跳广场舞了。到了11:00,‘玉湖’生鲜超市的送货车来到小区门口,张大爷给李阿姨打了个电话,两位大妈来到小区门口收了大闸蟹回去做午饭了。
无所事事的等待总是让人厌烦的,生活中到处都是异步调度例子,也符合人们的处理习惯,尤其是有多件事情要处理时。
回到JavaScript语言本身,在前端开发的过程中,我们对异步模式并不陌生:
l 当DOM树解析完的时候,我们可以做xxx。
l 当所有资源加载完毕的时候,我们可以做xxx。
l 当用户单击了这个按钮的时候,我们可以做xxx。
l …..
到了NodeJS,我们开发后端网络服务器程序的时候,依旧可以采用这样的模式:
l 当有客户端发送请求连接的时候,我们可以做xxx。
l 当有客户端有数据提交上来的时候,我们可以做xxx。
l 当网络连接断开的时候,我们可以做xxx。
从某种意义上说,当要处理一大堆并发的业务时,异步的基于事件驱动的编程模式比同步的阻塞模式效率要高的多。当然了,NodeJS也提供了一些同步处理的机制,用于在某些特定的场合使用,例如:要等条件A,条件B,条件C都满足的时候,才去做D这件事。
特点2:小而美,各司其职
NodeJS的整个框架是基于单线程事件驱动的异步式I/O,相比于Java,C++等多线程的机制,省去了维护线程的运行时环境的开销,当然,也迫使你在进行业务分析、模型架构的时候将大任务分解为一些小任务,体现了UNIX 系统中的专注做好一件事,小而美,各司其职的特点。因为是一个单线程,如果某个地方的处理出现了异常,那么整个程序就崩溃了,所以,对异常的处理要特别谨慎,时刻想到这里可能会发生什么异常。
特点3:云端管控模式npm
NodeJS基于功能的划分单位是模块,在程序设计时可以根据需要加载相关的模块,功能相近的模块可以组成一个包,从业务上看,跟Java的类库以及VC中的lib文件等类似,但是,包有一个重要的特性是:自解释的(之前只搞过Windows平台编程的我,第一次见到这种包的机制,内心还是有点小激动的,各位大牛轻拍)。什么意思呢?每个包都有一个package.json的包说明文件,里面说明了:这个包是用来干什么的?包含哪些部分?作者是谁?当前版本是什么?如何使用这个包?这个包依赖哪些包?测试用例是什么?…..等信息,CommonJS规范的体现,有了这种特性,再加上各个包可以在云端通过npm(NodeJS Package Manage)服务器来管理,这样在发布、调用、升级、维护起来的时候就非常方便,相关的程序读懂了这个包描述文件,就知道该怎么做了。
这么说有点抽象,那咱们就举个栗子吧。
如果你要在Windows上安装一个PHP服务器来玩玩,那么,你就要先安装一个Web服务器(例如:Apache),然后再安装PHP服务器,然后再在Apache里面配置相关的模块。如果遇到版本不匹配,配置信息错误,整了半天还是没能看到那句经典的Hello World!你的心情是崩溃的。(当然,现在也出了很多一键安装的集成软件包,咱这里主要是对比两种机制)
而来到NodeJS世界,你想搞一个Web服务器玩玩,你要做的就是打开命令行工具,然后输入:
npm install express //安装express框架
//安装完express框架之后执行
express –t ejs myWebSite //选用ejs模板引擎建立网站
//进入到目录myWebSite,执行
npm install //实现网站的安装
//安装完毕之后,执行
node app.js //启动Web服务器
每一步都是明确的,结构是清晰的,npm客户端工具与npm服务器之间基于包描述文件来沟通,依赖其他什么包?如何下载?版本如何匹配?都不用用户操心。
这种机制在Linux世界里貌似很常见,npm也传承了Linux社区的共享、共生的理念,是一个自由新世界。
特点4:基于底层的API,专为网络而来
既然是开发网络服务器,那么性能始终是一个重要的话题,如果单从JavaScript的语言性能,当然无法与C语言等编译型语言相比。但是,NodeJS牛X的地方在于,它把常见的网络功能模块,用C语言实现了,抽象成模块给JavaScript调用(具体怎么整的得问那些大神哈,我也不清楚其中的缘由,所以就不展开说了),这样就兼顾了性能和易用性,据说,整体的测评结果还非常不错,所以,核心模块用高效的语言来实现是NodeJS能够在服务器领域风靡开来的一个重要原因。
另外,一个方面,NodeJS提供的API接口都非常底层,也就说,不仅可以构建基于socket的网络服务,也可以实现HTTP服务器,如果你想搞一个基于浏览器的及时通讯平台,还可以用它来实现一个WebSocket服务器。
熟悉TCP/IP网络协议的朋友都知道,网络协议中的报文,往往是用Bit位来描述特性的,例如:第2位为0代表什么意思,第2位如果为1,又代表另外一个意思,要实现网络协议,不管是封装报文,还是解析报文,对“位”来操作都是绕不过去的。但是,JavaScript语言,对“位”操作的能力是极其有限的,效率底下,记得:JavaScript的大师级人物老道(Douglas Crockford)还忠告过大家,不要用JavaScript来执行“位”运算。面对各种各样的网络报文,该如何处理呢?这就又出现了NodeJS的精妙之处,引入了Buffer数据类型,专门用来处理二进制数据。
所以说,核心模块用C语言实现、提供了底层的API、引入了Buffer数据类型,是NodeJS非常适合开发网络服务器的重要原因。
当然啦,关于NodeJS的知识还有很多,也有一些非常知名的NodeJS框架,关于JavaScript的内容也有很多,更深入的了解,推荐大家看看诸位大牛写的文章和专著。下一篇开始,我们将以爱莲(iLinkIT)这个业务场景为起点,看看如何用NodeJS来达成我们的目标。
-----------------------爱莲(iLinkIT)系列文章------------------------------------------