本文将介绍Node.js的一些基本概念,包含它的历史,特性和简单的使用等。若是你有过服务端的编程经验,那么你将能很快熟悉它。javascript
这是Node.js官网上对其的定义,就是说,Node.js是一个javascript运行平台,该平台基于chrome v8 引擎。V8让Node.js在性能上获得了巨大的提高,由于它去掉了中间环节,执行的不是字节码,用的也不是解释器,而是直接编译成了本地机器码
。(注意:v8 5.9 发布后,Ignition 字节码解释器将默认启动,v8 又回到了字节码
的怀抱,具体请参阅:https://cnodejs.org/topic/590...)html
对一名前端而言,Node无疑有以下几个好处:前端
Node.js采用的是事件驱动、非阻塞I/O
的设计模型。你们想到了什么?这和javascript在浏览器上的运行机制是同样的。
另外,对于高并发的处理,传统平台采用的是多线程方案,而Node.js则采用的是单线程、事件驱动、非阻塞I/O
的设计模型。java
咱们来看一个浏览器中的例子:node
$.post('/resource.json', function (data) { console.log(data) }) // 继续执行
上面代码是浏览器中的一个ajax请求,假如该请求须要耗费600ms,该ajax请求会在事件轮询的外面执行(脚本执行的主顺序以外),而后当这个ajax请求完成时(600ms后),它会发出一个“事件
”,会有一个函数(一般称做“回调
”)来处理它。
这个操做是异步的,并不会“阻塞”脚本执行,事件轮询仍然能够响应页面上执行的其余交互或请求。这样,浏览器能够对客户作出响应,而且能够处理页面上的不少交互动做。 ajax
咱们再来看一个服务器中的例子:chrome
// 数据库查询操做 db.query('SELECT * FORM work', function (data) { console.log(data) } )
这段代码作了些I/O操做,而且在全部数据回来以前,这个进程并不会被阻塞。在Node中,I/O几乎老是在主事件轮询以外进行,使得服务器能够一直处于高效而且随时可以作出响应的状态,就像NGINX(带有异步I/O的事件轮询的一种http服务器)同样。这样进程不会受I/O限制,由于I/O延迟不会拖垮服务器。所以一些在服务器上曾经是重量级的操做,在Node服务器上仍然能够是轻量级
的。数据库
Node所针对的应用程序有一个专门的简称:DIRT。它表示数据密集型实时(data-intensive real-time)程序。上面已经提到,Node自身在I/O上很是轻量,能在处理大量请求时保持不少开放的链接,而且只占用一小部份内存
,因此,它特别擅长处理数据密集型实时应用。好比在线文档协做、对临近公交车的实时精肯定位,以及多人在线游戏等。编程
接下来咱们先看一些简单的例子。json
var fs = require('fs') fs.readFile('./package.json', 'utf8', function (er, data) { console.log(data) })
这段程序是要从硬盘里读取package.json文件。当全部数据都读出来后,就会调用那个回调函数。require('fs')
是指加载Node提供的文件模块,读取的文件内容将用utf8进行编码。
若是你有 PHP 开发经验,会知道在成功运行 PHP 以前先要配置一个功能强大而复杂的 HTTP 服务器,譬如Apache、IIS 或 Nginx,还须要将 PHP 配置为 HTTP 服务器的模块,或者使用 FastCGI 协议调用 PHP 解释器。这种架构是“浏览器 - HTTP 服务器 - PHP 解释器”的组织方式,而Node.js 将“HTTP服务器”这一层抽离,直接面向浏览器用户。以下图所示:
接下来,让咱们建立一个 HTTP 服务器吧。创建一个名为 app.js 的文件,代码以下:
var http = require('http') http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/html'}) res.write('<h1>Node.js</h1>') res.end('<p>Hello World</p>') }).listen(3000) console.log("HTTP server is listening at port 3000.")
上面代码中,建立HTTP服务器调用了http.createServer()
函数。它只有一个参数,是个回调函数,服务器每次
收到HTTP请求后都会调用这个回调函数。这个请求回调有两个参数,请求和响应对象,一般简写为req和res。服务器每收到一条HTTP请求,都会用新的req和res对象触发请求回调函数
。 res.writeHead()
方法设定了响应状态码为200和响应头中的Content-Type为text/html类型。response.write()
方法表示向请求的客户端发送响应内容。 内容能够是一个Buffer或字符串,表示要发送的内容。
Node不会自动往客户端写任何响应。在调用完请求回调函数以后,就要由你负责用res.end()
方法结束响应。因此,最终程序用res.end('<p>Hello World</p>')
结束了一次响应。
在终端中运行node app.js
命令,打开浏览器访问 http://127.0.0.1:3000
试试吧。
Node在处理数据流上也很强大。你能够把数据流当作特殊的数组,只不过数组中的数据分散在空间上,而数据流中的数据是分散在时间
上的。经过将数据一块一块地传送,开发人员能够每收到一块数据就开始处理,而不用等全部数据都到全了再作处理。
下面咱们看一个例子:
var fs = require('fs') var stream = fs.createReadStream('./package.json') stream.on('data', function (chunk) { console.log(chunk) }) stream.on('end', function () { console.log('finished') })
只要有新的数据块准备好,就会激发data事件,当全部数据块都加载完以后,会激发一个end事件。
程序能够边读取边处理,这要比等着全部数据都缓存到内存中再处理效率高得多
。
Node中也有可写数据流
,能够往里写数据块。当HTTP服务器上有请求过来时,对其进行响应的res对象就是可写数据流的一种。
可读和可写数据流能够链接起来造成管道,这是一种高效的数据处理方式,只要有数据准备好就能够处理,不用等着读取完整个资源再把它写出去。
用咱们上面的HTTP服务器,看看如何把一张图片流到客户端:
var http = require('http') var fs = require('fs') http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'image/png'}) fs.createReadStream('./img.png').pipe(res) }).listen(3000) console.log('Server running at http://localhost:3000/')
在这行代码中,数据从文件中读进来(fs.createReadStream),而后数据随着进来就被送到(.pipe)客户端(res)。在数据流动时,事件轮询还能处理其余事件。
相信读到这里,你们对Node的优点和特性已经有了一些了解,而且经过本文的三个编程小例子,对Node的一些用法也有了一些体会,Node跟全部技术同样,并非万能药。它擅长解决某些问题,并为咱们带来方便。一样的,在某些方面,倒是它的短板,好比:计算密集型应用。但愿你能在用Node开发以前,多一些合理的考虑,多一份编程的快乐。