【深刻浅出Node.js系列一】什么是Node.js

#0 系列目录#前端

#1 从名字提及# 有关Node.js的技术报道愈来愈多,Node.js的写法也是五花八门,有写成 NodeJS的,有写成Nodejs的,到底哪种写法最标准呢,咱们不妨遵循官方的说法。在Node.js的官方网站上,一直将其项目称之为”Node“或者”Node.js“, 没有发现其余的说法,”Node“用的最多,考虑到Node这个单词的意思和用途太普遍,容易让开发人员误解,咱们采用了第二种称呼——”Node.js“,js的后缀点出了Node项目的本意,其余的名称五花八门,没有确切的出处,咱们不推荐使用。node

#2 Node旨在解决什么问题# Node公开宣称的目标是 “旨在提供一种简单的构建可伸缩网络程序的方法”。当前的服务器程序有什么问题?咱们来作个数学题。在 Java™ 和 PHP 这类语言中,每一个链接都会生成一个新线程,每一个新线程可能须要 2 MB 的配套内存。在一个拥有 8 GB RAM 的系统上,理论上最大的并发链接数量是 4,000 个用户。随着您的客户群的增加,若是但愿您的 Web 应用程序支持更多用户,那么,您必须添加更多服务器。固然,这会增长服务器成本、流量成本和人工成本等成本。除这些成本上升外,还有一个潜在技术问题,即用户可能针对每一个请求使用不一样的服务器,所以,任何共享资源都必须在全部服务器之间共享。鉴于上述全部缘由,整个 Web 应用程序架构(包括流量、处理器速度和内存速度)中的瓶颈是:服务器可以处理的并发链接的最大数量web

Node 解决这个问题的方法是:更改链接到服务器的方式。每一个链接发射一个在 Node 引擎的进程中运行的事件,而不是为每一个链接生成一个新的 OS 线程(并为其分配一些配套内存)。Node 声称它毫不会死锁,由于它根本不容许使用锁,它不会直接阻塞 I/O 调用。Node 还宣称,运行它的服务器能支持数万个并发链接。编程

#3 Node.js不是JS应用、而是JS运行平台# 看到Node.js这个名字,初学者可能会误觉得这是一个Javascript应用,事实上,Node.js采用C++语言编写而成,是一个Javascript的运行环境。为何采用C++语言呢?据Node.js创始人Ryan Dahl回忆,他最初但愿采用Ruby来写 Node.js,可是后来发现Ruby虚拟机的性能不能知足他的要求,后来他尝试采用V8引擎,因此选择了C++语言。既然不是Javascript应用,为什么叫.js呢?由于 Node.js是一个Javascript的运行环境。提到Javascript,你们首先想到的是平常使用的浏览器,现代浏览器包含了各类组件,包括渲染引擎、Javascript引擎 等,其中Javascript引擎负责解释执行网页中的Javascript代码。做为Web前端 最重要的语言之一,Javascript一直是前端工程师的专利。不过,Node.js是一个后端的Javascript运行环境(支持的系统包括Linux、Windows),这意味着你能够编写系统级或者服务器端的Javascript代码,交给Node.js来解释执行,简单的命令相似于:后端

#node helloworld.js

Node.js采用了Google Chrome浏览器的V8引擎,性能很好,同时还提供了不少系统级的API,如文件操做、网络编程等。浏览器端的Javascript代码在运行时会受到各类安全性的限制,对客户系统的操做有限。相比之下,Node.js则是一个全面的后台运行时,为Javascript提供了其余语言可以实现的许多功能浏览器

#4 Node.js采用事件驱动、异步编程,为网络服务而设计# 事件驱动这个词并不陌生,在某些传统语言的网络编程中,咱们会用到回调函数,好比当socket资源达到某种状态时,注册的回调函数就会执行。Node.js的设计思想中以事件驱动为核心,它提供的绝大多数API都是基于事件的、异步的风格。以Net模块为例,其中的net.Socket对象就有如下事件:connect、data、 end、timeout、drain、error、close等,使用Node.js的开发人员须要根据本身的业务逻辑注册相应的回调函数。这些回调函数都是异步执行的,这意味着虽然在代码结构中,这些函数看似是依次注册的,可是它们并不依赖于自身出现的顺序,而是等待相应的事件触发。事件驱动、异步编程的设计,重要的优点在于,充分利用了系统资源,执行代码无须阻塞等待某种操做完成,有限的资源能够用于其余的任务。此类设计很是适合于后端的网络服务编程,Node.js的目标也在于此。在服务器开发中,并发的请求处理是个大问题,阻塞式的函数会致使资源浪费和时间延迟。经过事件注册、异步函数,开发人员能够提升资源的利用率,性能也会改善。安全

从Node.js提供的支持模块中,咱们能够看到包括文件操做在内的许多函数都是异步执行的,这和传统语言存在区别,并且为了方便服务器开发,Node.js的网络模块特别多,包括HTTP、DNS、NET、UDP、HTTPS、TLS等,开发人员能够在此基础上快速构建Web服务器。以简单的helloworld.js为例:服务器

// 全局方法require()是用来导入模块的,通常直接把require()方法的返回值赋值给一个变量,在JavaScript代码中直接使用此变量便可。require("http")就是加载系统预置的http模块。
var http = require('http');

// http.createServer是模块的方法,目的就是建立并返回一个新的web server对象,而且给服务绑定一个回调,用以处理请求。
http.createServer(function (req, res) {
    // 使用response.writeHead()函数发送一个HTTP状态200和HTTP头的内容类型(content-type)
    // 使用response.write()函数在HTTP相应主体中发送文本“Hello World"
    res.writeHead(200, {'Content-Type': 'text/plain'});
    // 完成响应
    res.end('Hello World\n');
// 经过http.listen()方法就可让该HTTP服务器在特定端口监听。
}).listen(80, "127.0.0.1");

// console.log就不用多说了,了解firebug的都应该知道,Node实现了这个方法。
console.log('Server running at http://127.0.0.1:80/');

上面的代码搭建了一个简单的http服务器(运行示例部署 在http://127.0.0.1中能够访问),在本地监听80端口,对于任意的http请求,服务器都返回一个头部状态码为200、Content-Type值为'text/plain'的"Hello World"文字响应。从这个小例子中,咱们能够看出几点:网络

  • Node.js的网络编程比较便利,提供的模块(在这里是http)开放了容易上手的API接口,短短几行代码就能够构建服务器。
  • 体现了事件驱动、异步编程,在createServer函数的参数中指定了一个回调函数(采用Javascript的匿名函数实现),当有http请求发送过来时,Node.js就会调用该回调函数来处理请求并响应。固然,这个例子相对简单,没有太多的事件注册,在之后的文章中读者会看到更多的实际例子。

当咱们使用 http.createServer 方法的时候,咱们固然不仅是想要一个侦听某个端口的服务器,咱们还想要它在服务器收到一个HTTP请求的时候作点什么。问题是,这是异步的:请求任什么时候候均可能到达,可是咱们的服务器却跑在一个单进程中。咱们建立了服务器,而且向建立它的方法传递了一个函数。不管什么时候咱们的服务器收到一个请求,这个函数就会被调用前端工程师

为何这种时间驱动对 Node 很理想?JavaScript 是一种很棒的事件驱动编程语言,由于它容许使用匿名函数和闭包,更重要的是,任何写过代码的人都熟悉它的语法。事件发生时调用的回调函数能够在捕获事件处进行编写。这样可使代码容易编写和维护,没有复杂的面向对象框架,没有接口,没有过分设计的可能性。只需监听事件,编写一个回调函数,其余事情均可以交给系统处理!

#5 Node.js的特色# 下面咱们来讲说Node.js的特色。事件驱动、异步编程的特色刚才已经详细说过了,这里再也不重复。

Node.js的性能不错。按照创始人Ryan Dahl的说法,性能是Node.js考虑的重要因素,选择C++和V8而不是Ruby或者其余的虚拟机也是基于性能的目的。Node.js在设计上也是比较大胆,它以单进程、单线程模式运行(很吃惊,对 吧?这和Javascript的运行方式一致),事件驱动机制是Node.js经过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文切换,这意味着面对大规模的http请求,Node.js凭借事件驱动搞定一切,习惯了传统语言的网络服务开发人员可能对多线程并发和协做很是熟悉,可是面对 Node.js,咱们须要接受和理解它的特色。由此咱们是否能够推测出这样的设计会致使负载的压力集中在CPU(事件循环处理?)而不是内存(还记得Java虚拟机抛出OutOfMemory异常的日子吗?),眼见为实,不如来看看淘宝共享数据平台团队对Node.js的性能测试:

  • 物理机配置:RHEL 5.二、CPU 2.2GHz、内存4G
  • Node.js应用场景:MemCache代理,每次取100字节数据
  • 链接池大小:50
  • 并发用户数:100
  • 测试结果(socket模式):内存(30M)、QPS(16700)、 CPU(95%)

从上面的结果,咱们能够看到在这样的测试场景下,qps可以达到16700次,内存仅占用30M(其中V8堆占用22M),CPU则达到95%,可能成为瓶颈。此外,还有很多实践者对Node.js作了性能分析,总的来讲,它的性能让人信服, 也是受欢迎的重要缘由。既然Node.js采用单进程、单线程模式,那么在现在多核硬件流行的环境中,单核性能出色的Node.js如何利用多核CPU呢?创始人Ryan Dahl建议,运行多个Node.js进程,利用某些通讯机制来协调各项任务。目前,已经有很多第三方的Node.js多进程支持模块发布,后面的文章会详细讲述Node.js在多核CPU下的编程。

Node.js的另外一个特色是它支持的编程语言是Javascript。关于动态语言和静态语言的优缺点比较在这里再也不展开讨论。只说三点:

  1. Javascript做为前端工程师的主力语言,在技术社区中有至关的号召力。并且,随着Web技术的不断发展,特别是前端的重要性增长,很多前端工程师开始试水”后台应用“,在许多采用Node.js的企业中,工程师都表示由于习惯了Javascript,因此选择Node.js。
  2. Javascript的匿名函数和闭包特性很是适合事件驱动、异步编程,从helloworld例子中咱们能够看到回调函数采用了匿名函数的形式来实现,很方便。闭包的做用则更大,看下面的代码示例:
var hostRequest = http.request(requestOptions,f unction(response) {
    var responseHTML =''; 
    response.on('data', function (chunk) {
        responseHTML = responseHTML + chunk;    
    });
    response.on('end',function(){ 
       console.log(responseHTML);
       // do something useful
    });
});

在上面的代码中,咱们须要在end事件中处理responseHTML变量,因为Javascript的闭包特性,咱们能够在两个回调函数以外定义responseHTML变量,而后在data事件对应的回调函数中不断修改其值,并最终在end事件中访问处理。

  1. Javascript在动态语言中性能较好,有开发人员对Javacript、Python、Ruby等动态语言作了性能分析,发现Javascript的性能要好于其余语言,再加上V8引擎也是同类的佼佼者,因此Node.js的性能也受益其中。选择Node.js有许多方面的缘由,好比考虑了兴趣及社区发展,同时也但愿能够提升并发能力,榨干CPU
相关文章
相关标签/搜索