首先介绍下什么是nodejavascript
1,单线程前端
node保持了javascript在浏览器中单线程的特色,Node中,Javascript与其他线程没法共享任何状态。java
单线程好处:不用到处在乎状态的同步,没有死锁,也没有线程上下文切换带来的性能开销。node
单线程坏处:没法利用多核cpu,错误会引发整个应用退出,应用的健壮性值得考验,大量计算占用CPU没法继续调用异步I/O。git
(注意:针对这些单线程坏处,node都有解决方案,这里不谈)es6
2,跨平台 (基于libuv)github
兼容Windows和*nix平台主要得益于Node在架构层的的改动,它在操做系统与Node与操做系统之间构建了一层平台层框架,即libuv。目前,libuv已是许多系统实现跨平台的基础组件。web
经过良好的架构,Node的第三方C++模块也能够借助libuv实现跨平台,目前,除了没有保持更新的C++模块外,大部分C++模块都能实现跨平台的兼容。apache
Java有类文件,Python有import机制,Ruby有require,PHP有include和require。浏览器端Javascript是没有标准的模块机制的,只能经过<script>标签引入代码显得杂乱无章,npm
语言自己没有组织和约束能力,开发者不得不经过命名空间等方式人为约束代码。-》AMD,CMD。
CommonJS规范:但愿javascript可以在任何地方运行。
CommonJS的规范提出主要是为了弥补当前Javascript没有标准的缺陷,以达到像Python,Ruby和Java具有开发大型应用的基础能力,而不是停留在小脚本程序的阶段.NodeJS是这种规范的实现
CommonJS规范涵盖了模块,二进制,Buffer,字符集编码,I/O流,进程环境,文件系统,套接字,单元测试,Web服务网管接口,包管理等。
CommonJS有不少实现,其中不乏不少大名鼎鼎的项目,好比 说:Apache的CouchDB和node.js等。但这些项目大 部分只实现了CommonJS的部分规范。具体的项目和实现部分参见官方网站的说 明:http://commonjs.org/impl/
Node模块实现
4,应用场景
I/O密集型
是否不擅长cpu密集型?
但凡这种「既是单线程又是异步」的语言有一个共同特色:它们是 event-driven 的。驱动它们的 event 来自一个异构的平台。
异步调用(封装参数)-》线程池(iocp)-》事件循环(监听者-》执行回调函数)
[注]:操做系统对计算机进行了抽象,将全部输入输出设备抽象为文件,内核在进行文件I/O操做时,经过文件描述符进行管理,而文件描述符相似于应用程序与系统内核
之间的凭证。应用程序若是须要进行I/O调用,须要先打开文件描述符,而后根据文件描述符去实现文件的数据读写。此处阻塞/O与非阻塞I/O的区别在于阻塞I/O完成整个获取
数据的过程,而非阻塞I/O则不带数据直接返回,要获取数据,还须要经过文件描述符再次读取。
阻塞I/O的一个特色是必定要等待系统内核层面完成全部数据操做后,调用才结束。以读取磁盘文件为例:系统内核在完成磁盘寻道,读取数据,复制数据到内存中以后这个调
用才结束。如图:
阻塞I/O形成了CPU等待,浪费了等待时间,CPU的处理能力不能获得充分利用。为了提升性能,内核提升了非阻塞I/O。非阻塞I/O跟阻塞I/O的区别为调用以后当即返回,如图:
非阻塞I/O返回以后,CPU的时间片能够用来处理其余事务,此时性能提高是明显的。
但非阻塞I/O也存在一些问题。因为完整的I/O没有完成,当即返回并非业务层指望的数据,而仅仅是打当前调用的状态,为了获取完整的数据,应用层序须要重复调用I/O操做来
确认是否完成。这种重复的调用判断操做是否完成的技术叫作轮询。[注]:任意技术都并不是是完美的,阻塞I/O形成CPU等待浪费,非阻塞I/O带来的麻烦倒是须要轮询取确认是否
彻底完成数据获取,他会让CPU处理状态判断,是对CPU的资源浪费。
轮询技术是有演进的,以减小I/O状态判断的CPU损耗。从read->select->poll->epoll。具体状况这里不谈。
理想的非阻塞异步I/O:咱们指望的完美的异步I/O应该是应用程序发起非阻塞调用,无需经过遍历或者事件唤醒灯方式轮询,能够直接处理下一个任务,只须要在I/O完成后经过信号
或者回调函数讲数据传递给应用程序便可,以下图:
幸运的是,在Linux中存在这中方式,它提供一个异步的I/O方式(AIO)就是经过信号或回调来传递数据的。但不幸的是,只有Linux中有,而且AIO只支持内核I/O中的O_DIRECT方法
读取,而且没法利用系统缓存。
现实确定比理想要骨感一些,可是要达成异步I/O的目标,也并不是难事。前面咱们讲场景都限定在单线程的状态下,多线程的方式就是另外一番风景了。经过让部分线程进行阻塞I/O
或者非阻塞I/O加轮询技术来完成数据获取,让一个线程进行计算,经过线程之间的同窗讲I/O获得数据进行传递,这就轻松实现了异步I/O(尽管是模拟的)。
[注]:这里的I/O不只仅只局限于磁盘读写*nix将计算机抽象了一番,磁盘文件,硬件,套接字等几乎全部计算机资源都被抽象成了文件,所以这里的描述的阻塞和非阻塞的状况
一样适合套接字等。
[注]:咱们虽然时常提到Node是单线程的,这里的单线程仅仅指的是Javascript执行在但造成中罢了。在Node中,不管是什么平台,内部完成的I/O任务都是另有线程池的。
3,为何要用异步?
Deferred是前端解决异步操做的一种编程范式,后来出现的Promise规范更是让其普适性大大提升。不过Promise规范也存在分岐。如今最流行的是Promise/A+规范。
一个兼容 ES6 Promises 的Polyfill类库。 它基于 RSVP.js 这个兼容 Promises/A+ 的类库, 它只是 RSVP.js 的一个子集,只实现了Promises 规定的 API。
这是一个独立版本的 YUI 的 Promise Polyfill,具备和 ES6 Promises 的兼容性。
Promise
扩展类库 使用过Node.js的人可能会知道Q
模块,Q
实现了Promises
和 Deferreds
等规范,在Node.js中环境或浏览器环境中使用。
一个Promise/A+
简单实现模块,除实现then
方法外,还扩展一些标准外的方法,在Node.js中环境或浏览器环境中使用。
bluebird
类库除了兼容Promise
规范以外,还对Promise
对象进行了必定的扩展,如:取消promise对象的运行等。另外,还在运行效率上进行了必定的优化。bluebird
也是一 个npm
模块,能够在Node.js中环境或浏览器环境中使用。
其余
《深刻浅出node》做者朴灵写的
EventProxy参考:
https://github.com/JacksonTian/eventproxy
Wind.js https://github.com/JeffreyZhao/wind http://blog.fens.me/nodejs-async-windjs/