为什么要用 Node.js
1、传统意义上的 JavaScript 运行在浏览器上,这是因为浏览器内核实际上分为两个部分:渲染引擎和 JavaScript 引擎。前者负责渲染 HTML + CSS,后者则负责运行 JavaScript。Chrome 使用的 JavaScript 引擎是 V8,它的速度非常快。Node.js 是一个运行在服务端的框架,它的底层就使用了 V8 引擎。我们知道 Apache + PHP 以及 Java 的 Servlet 都可以用来开发**页,Node.js 的作用与他们类似,只不过是使用 JavaScript 来开发。从定义上介绍完后,举一个简单的例子,新建一个 app.js 文件并输入以下内容:

5、第三方模块:

8、默认的负载均衡规则是把网络请求依次分配到不同的端口,我们可以用 least_conn 标志把网络请求转发到连接数最少的 Node.js 进程,也可以用 ip_hash 保证同一个 ip 的请求一定由同一个 Node.js 进程处理。多个 Node.js 进程可以充分发挥多核 CPU 的处理能力,也具有很强大的拓展能力。事件循环在 Node.js 中存在一个事件循环(Event Loop),有过 iOS 开发经验的同学可能会觉得眼熟。没错,它和 Runloop 在一定程度上是类似的。一次完整的 Event Loop 也可以分为多个阶段(phase),依次是 poll、check、close callbacks、timers、I/O callbacks 、Idle。由于 Node.js 是事件驱动的,每个事件的回调函数会被注册到 Event Loop 的不同阶段。比如 fs.readFile 的回调函数被添加到 I/O callbacks, setImmediate 的回调被添加到下一次 Loop 的 poll 阶段结束后, process.nextTick() 的回调被添加到当前 phase 结束后,下一个 phase 开始前。不同异步方法的回调会在不同的 phase 被执行,掌握这一点很重要,否则就会因为调用顺序问题产生逻辑错误。Event Loop 不断的循环,每一个阶段内都会同步执行所有在该阶段注册的回调函数。这也正是为什么我在网络 I/O 部分提到,不要在回调函数中调用阻塞方法,总是用异步的思想来进行耗时操作。一个耗时太久的回调函数可能会让 Event Loop 卡在某个阶段很久,新来的网络请求就无法被及时响应。由于本文的目的是对 Node.js 有一个初步的,全面的认识。就不详细介绍 Event Loop 的每个阶段了,具体细节可以查看 官方文档 。可以看出 Event Loop 还是比较偏底层的,为了方便的使用事件驱动的思想,Node.js 封装了 EventEmitter 这个类:

10、利用管道技术,可以把一个流中的内容写入到另一个流中:

12、总结对于高并发的长连接,事件驱动模型比线程轻量得多,多个 Node.js 进程配合负载均衡可以方便的进行拓展。因此 Node.js 非常适合为 I/O 密集型应用提供服务。但这种方式的缺陷就是不擅长处理 CPU 密集型任务。Node.js 中通常以流的方式来描述数据,也对此提供了很好的封装。Node.js 使用前端语言(JavaScript) 开发,同时也是一个后端服务器,因此为前后端分离提供了一个良好的思路。我会在下一篇文章中对此进行分析。