node.js 是一个服务器端运行JavaScript脚本的环境,这个环境下保持了客户端JavaScript的api一致,并且强制使用单进程单线程模式下工作的方式也与运行在浏览器宿主下的javascript保持一致,看似没有其他服务器端语言的任何优势,错了,上面提到的单进程单线程模式其实就是它的一大优点.
单线程+单进程
(1)程序大部分api与客户端javascript保持一致(当然服务器端javascript可以随意执行io操作及调用一些系统层面的接口)
(2)javascript语言历史悠长,门槛不高,涉及到javascript语言的工程师多如牛毛
(3)单线程单进程模式促使程序执行上下文不需要向其他服务器端语言一样切换运行时上下文,运行状态加锁,解锁等操作
既然node.js 在运行模式上与客户端javascript保持一致,那么客户端javascript中遇到的如下情况在node.js中一定也存在,如下事例代码$(function(){
console.log('ajax 读取数据开始');
$.ajax({
type:'post',
url:'http://www.yijiebuyi.com/ajax',
data:{t:'test'},
dataType:'JSON',
success:function(result){
result.status?console.log('ajax 获取数据成功'):console.log('ajax 获取数据失败');
}
});
console.log('ajax 读取数据结束');
});
上面是一个简单的jquery 读取服务器端数据事例代码,写过客户端javascript的童鞋一定明白,javascript是天生的异步回调模式.所以上面的执行结果必然是如下方式显示:ajax 读取数据开始
ajax 读取数据结束
ajax 获取数据成功
node.js 的运行模式和客户端javascript保持一致,也是异步回调,此模式可能在编写代码的时候很难控制执行顺序,但这恰恰是node.js的另外一大优点
异步+回调
异步导致程序执行时不等待,如果不等待如何获取到程序运行结果?这正是回调的作用.
简单粗暴的理解就是:你该运行程序就专心运行你的程序,不要动不动就询问我返回值到了没有,如果有了返回值我会主动告诉你.
这一点完全和绝大部分服务器端运行程序不一样,有人肯定又怀疑了,服务器端运行的语言是和服务器IO打交道的,node.js执行IO不可能也是异步吧?
还真是这样,node.js 创始人花了心血实现了node.js的异步IO运行模式,这样才更能突出node.js 在服务器端语言中的高效手段.
为什么?
首先大家应该理解IO ?如果你觉得读取文件是IO操作,好像也没有问题,但是视野应该更广阔一点,计算机世界中所有所有的输入/输出统称为IO操作.
这时再来理解node.js的异步IO为何高效,我们编译好的程序会运行在一个程序空间中,程序空间的代码如何和计算机交互,就是发送指令到内核空间,真正的逻辑运行都在内核空间中完成,如果是其他服务器端语言,会等待内核空间运算完成并返回执行结果后才接着执行程序空间中的下一段指令,node.js 在这一过程中是不等待内核空间,而是直接挨个执行程序空间的所有指令.
如果我们完成一个小模块需要向内核空间发送3次指令,三次指令耗时分别是 a,b,c
传统服务器端语言耗时是 a+b+c
node.js 的耗时是 max(a,b,c);
这里大概有人会有疑问了,既然node.js 运行时不管不顾内核空间的运行状态和结果,而且还不主动去询问内核空间是否计算出了结果?那它的返回值是如何得到的?
这就又涉及到node.js的另外一个优点了.
事件轮询
其实node.js在整体设计上就是一个观察者模式,如果你了解观察者模式的话,当一个条件满足时,会马上触发这个事件上的绑定方法(也就是回调函数)
也就是说程序空间在每一次向内核空间发射指令时,其实就是在一个事件栈里压入了一个事件,而每个事件都会绑定一个触发事件的方法(就是node.js的回掉函数)node.js会专门是轮询遍历这个事件栈,直到所有事件都处理完,而遍历到的每一个事件都会触发回调函数,把运行结果带回给程序空间,这是我们才能拿到回调函数里面的内容.当事件非常多时,这个轮询可能成为服务器的一个瓶颈(即CPU消耗特别高)
当然node.js也有很多不足,单进程单线程模式可能对于多核cpu是一个浪费,但是我们也有解决方案,node.js还在高速发展中,相信以后会越来越强大!