文章目录
1.1Node诞生
- 2009年3月,Ryan Dahl在其博客宣布准备基于V8创建一个轻量级的web服务器
- 2009年5月,发布最初的版本
1.2 Node的命名与起源
Node名字来源和它起源密切相关
1.2.1为什么是javascript
作者是一名资深c/c++开发,在创建Node之前,主要工作都是围绕高性能web服务器进行的。设计高性能和web服务器的几个要点:事件驱动、非阻塞I/O。考虑到高性能、符合事件驱动、没有历史包袱这3个主要原因,javascript称为了Node的实现语言。
1.2.2为什么叫Node
Node发展为一个强制不共享任何资源的单线程、单进程系统,包含十分适宜网络的库,为构建大型分布式应用程序提供基础设施,其目标也是称为一个构建快速、可伸缩的网络应用平台。它自身非常简单,通过协议来组织许多Node,非常容易通过扩展来达成大型网络应用的目的。每一个Node进程都构成这个网络应用中的一个节点,这是它名字所含意义的真谛。
1.3Node给javascript带来的意义
我们知道浏览器中除来V8作为浏览器的引擎外,还有一个webkit布局引擎。Node结构与Chrome十分相似。他们都是基于事件驱动的异步架构,浏览器通过事件驱动来服务界面上的交互,Node通过事件驱动来服务I/O。在Node中,javascript可以随心所欲地访问本地文件,可以搭建websocket服务器端,可以连接数据库,可以如web workers一样玩转多进程。
1.4 Node的特点
作为后端js的运行平台,Node保留了前端浏览器js中那些熟悉的接口,没有改写语言本身的任何特性,依旧基于作用域和原型链,区别在于它将前端中广泛运用的思想迁移到了服务器端。
1.4.1 异步I/O
关于异步I/O,下面代码可以发起一个Ajax请求
$.post('/url',{title:'深入简出Node'},function (data) {
console.log('收到相应')
})
console.log('发送ajax结束')
熟悉异步的用户必然知道,收到相应是在发送ajax结束之后输出的。在调用$.post后后续代码是被立即执行的,而收到相应的执行时间是不被预期的。异步调用中对于结果的捕获是符合:注重结果,不关心过程的一种表现。
在Node中,异步I/O也是常见的。以读取文件为例,我们可以看到它与前端ajax调用的方式是极其类似的
var fs = require('fs')
fs.readFile('path',function(err,file){
console.log('读取文件完成')
})
console.log('发起读取文件')
在Node中,我们可以从语言层面很自然地进行并行I/O操作。每个调用之间无需等待之前的I/O调用结束。在编程模型上极大提升效率。
对于同步I/O而言,他们耗时是两个任务的耗时之和。这里异步带来的优势是显而易见的。
1.4.2 事件与回调函数
Node是将前端浏览器中应用广泛且成熟的事件引入后端,配合异步I/O,将事件点暴露给业务逻辑
下面例子展示的是Ajax异步提交的服务器端处理过程。Node创建一个web服务器,并侦听8080端口。对于服务器,我们为其绑定了request事件,对于请求事件我们绑定data事件和end事件
var http = require('http')
var querystring = require('querystring')
// 侦听服务器的request事件
http.createServer(function(req,res){
var postData = '';
req.setEncoding('utf8')
// 侦听请求的data
req.on('data',function(chunk){
postData += chunk
});
// 侦听请求的end事件
req.on('end',function(){
res.end(postData)
})
}).listen(8080)
console.log('服务器启动完成')
在前端为AJAX请求绑定了success事件,在发出请求后,只需关心请求成功时执行相应的业务逻辑即可,相关代码
$.ajax({
'url':'/url',
'method':'POST',
'data':{},
'success':function(data){
// success事件
}
})
事件的编程具有轻量级、松耦合、只关注事物点等优势,但是在多个异步任务的场景下,事件与事件之间各自独立,如何协作是一个问题。
回调函数无数不在,因为在js中,我们将函数作为第一等公民来对待,可以将函数作为对象传递给方法作为实参进行调用。
与其他后端语言对比,Node除了异步和事件外,回调函数是一大特色。纵观下来,回调函数也是最好的接受异步调用返回数据的方式。
1.4.3 单线程
Node保持了js在浏览器中单线程的特点。在Node中,js与其余线程是无法共享任何状态的。单线程的最大好处是不用像多线程编程那样处处在意状态的同步问题,这里没有死锁的存在,也没有线程上下文交换带来的性能上的开销
同样,单线程也有它自身的弱点,这些弱点是学习Node的过程中必须要面对的。
单线程的弱点
- 无法利用多核CPU
- 错误会引起整个应用退出,应用的健壮性值得考验
- 大量计算占用CPU导致无法继续调用异步I/O
浏览器中的js与UI公用一个线程一样,js长时间执行会导致UI的渲染和响应中断。在Node中,长时间的CPU占用也会导致后续的异步I/O发不出调用,已完成的异步I/O的回调函数也会得不到及时执行
1.4.4 跨平台
起初只可以在linux上运行。如果想要在windows上使用,必须通过Cygwin或者minGW,现在Node已经可以在windows上运行了,兼容windows和*nix主要得益于Node在架构层面的改动,他在操作系统与Node上层模块系统构建了一层平台架构
1.5Node的应用场景
关于Node,探讨较多的主要有I/O密集型和CPU密集型
1.5.1 I/O密集型
从单线程的家都来说,Node处理I/O的能力是值得称赞的。通常说Node擅长I/O密集型的应用场景基本上是没人反对的。Node面向网络且擅长并行I/O,能够有效地组织起更多的硬件资源。
1.5.2 是否不擅长CPU密集型业务
实际上V8的执行效率十分高,单以执行效率来评判,V8的执行效率是母庸置疑的。
CPU密集型应用其实并不可怕。CPU密集型应用给Node带来的挑战主要有:由于js单线程原因,如果长时间运行的计算(比如大循环),将会导致CPU事件片不能释放,使得后续I/O无法发起。但是适当调整和分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起,这样即可同时享受收到并行异步I/O的好处,又能充分利用CPU
Node虽然没有提供多线程的方式进行计算。Node虽然没有提供多线程用于计算支持,但是有下面两个方法来充分利用CPU
- Node可以通过编写C/C++扩展的方式更高效的利用CPU,将一些V8不能做到性能极致的地方通过C/C++实现。
- 如果单线程的Node不能满足需求,甚至用了C/C++扩展后还觉得不够,可以通过子进程的方式,将一部分Node进程当作常驻服务进程进行计算。然后利用进程间的消息来传递结果,将计算与I/O分离,这样还能充分利用多CPU。CPU密集不可怕,如何合理调度是诀窍。
1.5. 3 与遗留系统和平共处
旧的系统具有非常稳定的数据输出,持续为传统网站服务,同时移动版提供数据源,Node将该数据源当作数据接口,发挥异步并行的优势,而不用关心它背后是用什么语言实现的。
1.5.4 分布式应用
分布式应用意味着对可伸缩性的要求非常高。数据平台通常要在一个数据库群中寻找需要的数据。阿里开发了中间层NodeFox、ITier,将数据库集群做了划分和映射,查询调用依旧是针对单张表进行Sql查询,中间层分解查询Sql,并行地去多台数据库中获取数据并合并。NodeFox能实现对多台Mysql数据的查询,如同查询一台Mysql一样,而ITier更强大,查询多个数据库如同查询单个数据库一样。这里多个数据库指的是不同的数据库。
1.6 Node的使用者
- 前后端编程语言环境统一
- Node带来的高性能I/O用于实时应用
- 并行I/O使得使用者可以高效地利用分布式环境
- 云计算平台提供Node支持
- 游戏开发领域
- 工具类应用