日期:2014-05-16  浏览次数:20417 次

转:我为什么向后端工程师推荐NodeJS

出自http://cnodejs.org,转载请注明出处和作者
作者:limu
原文:http://cnodejs.org/blog/?p=780

上周末参与了CNodeJS社区的第一次北京聚会,现场气氛非常的好.而作为一名前端开发,我在后面的讨论环节讲了下我对NodeJS的看法,主要回答的问题是”我为什么会向后端工程师推荐NodeJS”.这其实是去年年底大团队技术总结的话题之一,包含在我之前发过的PPT:团队年终技术Review中.因为之前没有准备,当天仓促上阵,也不知道说清楚了没,不如就在这里再详细展开记录下.

我想不仅仅是NodeJS,当我们要引入任何一种新技术前都必须要搞清楚几个问题:
1.我们遇到了什么问题?
2.这项新技术解决什么问题,是否契合我们遇到的问题?
3.我们遇到问题的多种解决方案中,当前这项新技术的优势体现在哪儿?
4.使用新技术,带来哪些新问题,严重么,我们能否解决掉?

我们的问题:Server端阻塞
NodeJS被设计用来解决服务端阻塞问题.通过一段简单的代码解释何为阻塞:

//根据ID,在数据库中Persons表中查出Name
var?name?=?db.query("selcect?name?from?persons?where?id=1");
//进程等待数据查询完毕,然后使用查询结果.
output("name");

这段代码的问题是在上面两个语句之间,在整个数据查询的过程中,当前程序进程往往只是在等待结果的返回.这就造成了进程的阻塞.对于高并发,I/O密集行的网络应用中,一方面进程很长时间处于等待状态,一方面为了应付新的请求不断的增加新的进程.这样的浪费会导致系统支持QPS远远小于后端数据服务的QPS,成为系统的瓶颈.而且这样的系统也特别容易被慢链接攻击(客户端故意不接收或减缓接收数据,加长进程等待事件).

如何解决阻塞问题
解决这个问题的办法是,建立一种事件机制,发起查询请求之后,立即将进程交出,当数据返回后触发事件,再继续处理数据:

//定义如何后续数据处理函数
function?onDataLoad(name){
	output("name");
}
//发起数据请求,同时指定数据返回后的回调函数
db.query("selcect?name?from?persons?where?id=1",onDataLoad);

我们看到按照这个思路解决阻塞问题,首先我们要提供一套高效的异步事件调度机制.而主要用于处理浏览器端的各种交互事件的JavaScript.相对于其他语言,至少有两个关键点特别适合完成这个任务.
为什么JS适合解决阻塞问题
首先JavaScript是一种函数式编程语言,函数编程语言最重要的数学基础是λ演算(lambda calculus) — 即函数可以接受函数当作输入(参数)和输出(返回值).
函数可以作为其他函数的参数输入的这个特性,使得为事件指定回调函数变得很容易.特别是JavaScript还支持匿名函数.通过匿名函数的辅助,之前的代码可以进行简写如下.

db.query("selcect?name?from?persons?where?id=1",function(name){
	output(name);
});

还有一个关键问题是,异步回调的运行上下文保持(称状态保持),我看一段代码来说明何为状态保持.

//传统同步写法:将查询和结果打印抽象为一个方法
function?main(){
	var?id?=?"1";
	var?name?=?db.query("selcect?name?from?persons?where?id="?+?id);
	output("person?id:"?+?id?+?",?name:"?+?name);
}
main();

前面的写法在传统的阻塞是编程中非常常见,但接下来进行异步改写时会遇到一些困扰.

//异步写法:
function?main(){
	var?id?=?"1";
	db.query("selcect?name?from?persons?where?id="?+?id,function(name){
		output("person?id:"?+?id?+?",?name:"?+?name);//n秒后数据返回后执行回调
	});
}
main();

细心的同学可以注意到,当等待了n秒