前言本文将介绍Node.js的一些基本概念,包括它的历史、特点和简单使用。如果您有服务器端编程经验,那么您将能够很快熟悉它。什么是Node.js这是Node.js官网的定义,也就是说Node.js是一个基于chromev8引擎的javascript运行平台。V8大大提高了Node.js的性能,因为它去掉了中间环节,执行的不是字节码,也没有使用解释器,而是直接编译成本地机器码。(注:v85.9发布后,会默认启动Ignition字节码解释器,v8又回到了字节码的怀抱。具体可以参考:https://cnodejs.org/topic/590...)Node.jsBenefits对于前端来说,Node无疑具有以下优势:开发者可以用一种语言编写整个Web应用程序,可以减少开发客户端和服务器时所需的语言切换。一些NoSQL数据库使用JavaScript语言(例如CouchDB和MongoDB),因此使用它们非常方便。Node使用的虚拟机(V8)将严格遵循ECMAScript标准。换句话说,如果你想在Node中使用新的JavaScript语言特性,你不必等到所有浏览器都支持它们。特性Node.js使用事件驱动、非阻塞I/O设计模型。你怎么看?这与javascript在浏览器上运行的机制相同。此外,对于高并发处理,传统平台采用多线程方案,而Node.js采用单线程、事件驱动、非阻塞I/O设计模型。我们在浏览器中看一个例子:$.post('/resource.json',function(data){console.log(data)})//继续执行上面的代码是浏览器中的ajax请求,如果请求耗时600ms,ajax请求会在事件循环外(脚本执行的主序列外)执行,然后当ajax请求完成时(600ms后),会发出一个“事件”,会有一个函数(通常称为“回调”)来处理它。此操作是异步的,不会“阻止”脚本执行,事件循环器仍然可以响应页面上执行的其他交互或请求。这样,浏览器就可以响应客户端,并可以处理页面上的许多交互。再看服务器中的另一个例子://数据库查询操作db.query('SELECT*FORMwork',function(data){console.log(data)})这段代码做了一些I/O操作,以及流程在所有数据返回之前不会阻塞。在Node中,I/O几乎总是在主事件循环之外完成,因此服务器始终高效并准备好响应,就像NGINX(具有异步I/O的事件循环)那种http服务器)。这样,进程就不会受I/O限制,因为I/O延迟不会使服务器不堪重负。所以一些以前在服务器上是重量级的操作,在Node服务器上仍然可以是轻量级的。Node针对应用程序的污垢程序有一个特殊的缩写:DIRT。它代表数据密集型实时程序。上面说了,Node本身在I/O方面是非常轻量级的,在处理大量请求的时候可以保持很多打开的连接,而且只占用很少的内存,所以特别擅长处理数据密集型的实时-时间应用。例如在线文档协作、附近公交车的实时精确定位、多人在线游戏等。简单示例接下来,让我们看一些简单的示例。文件操作varfs=require('fs')fs.readFile('./package.json','utf8',function(er,data){console.log(data)})这个程序是从硬盘读取disk读取package.json文件。读取完所有数据后,将调用该回调函数。require('fs')指的是加载Node提供的文件模块,读取的文件内容会进行utf8编码。HTTP服务器如果你有PHP开发经验,你就会知道,要想成功运行PHP,首先要配置一个强大而复杂的HTTP服务器,比如Apache、IIS或Nginx,同时你还需要将PHP配置为HTTP服务器,或者使用FastCGI协议调用PHP解释器。这种架构是“浏览器-HTTP服务器-PHP解释器”的组织,Node.js抽离了“HTTP服务器”这一层,直接面向浏览器用户。如下图所示:接下来我们来创建一个HTTP服务器。使用以下代码创建一个名为app.js的文件:varhttp=require('http')http.createServer(function(req,res){res.writeHead(200,{'Content-Type':'text/html'})res.write('
Node.js
')res.end('HelloWorld
')}).listen(3000)console.log("HTTP服务器是在端口3000上监听。”)在上面的代码中,调用了http.createServer()函数来创建一个HTTP服务器。它只有一个参数,就是一个回调函数,服务端每收到一个HTTP请求都会调用这个回调函数。请求回调有两个参数,request和response对象,通常简写为req和res。服务器每收到一个HTTP请求,就会使用新的req和res对象触发请求回调函数。res.writeHead()方法将响应状态码设置为200,并将响应头中的Content-Type设置为text/html。response.write()方法表示将响应内容发送给请求客户端。content可以是Buffer或表示要发送的内容的字符串。Node不会自动向客户端写入任何响应。调用请求回调函数后,您可以使用res.end()方法结束响应。因此,最终程序以res.end('HelloWorld
')结束响应。在终端运行nodeapp.js命令,打开浏览器访问http://127.0.0.1:3000试试看。流节点在处理数据流方面也很强大。你可以把数据流想象成一个特殊的数组,只不过数组中的数据在空间上是分散的,而数据流中的数据在时间上是分散的。通过逐条发送数据,开发人员可以在收到每条数据时开始处理,而不是等待所有数据到达后再进行处理。让我们看一个例子:varfs=require('fs')varstream=fs.createReadStream('./package.json')stream.on('data',function(chunk){console.log(chunk)})stream.on('end',function(){console.log('finished')})只要有新的数据块准备好,就会触发data事件,当所有数据块都加载完成后,一个结束事件。程序可以边读边处理,这比等待所有数据都缓存到内存中再处理效率要高得多。Node中还有一个可写的数据流,可以向其中写入数据块。当请求来自HTTP服务器时,响应它的res对象是一种可写数据流。可读和可写的数据流可以连接起来形成一个管道,这是一种高效的数据处理方式,只要有数据准备好就可以处理,而不是等着读完整个资源再写出来。使用我们上面的HTTP服务器来查看如何将图像流式传输到客户端:varhttp=require('http')varfs=require('fs')http.createServer(function(req,res){res.writeHead(200,{'Content-Type':'image/png'})fs.createReadStream('./img.png').pipe(res)}).listen(3000)console.log('服务器运行于http://localhost:3000/')这行代码是从文件(fs.createReadStream)中读取数据,然后在数据进来的时候将数据发送(.pipe)到客户端(res)。事件循环可以还在数据流动时处理其他事件。小结相信看完本文,你已经对Node的优势和特点有了一定的了解,通过本文的三个小编程实例,你也对Node的一些用法有了一定的体会。与所有技术一样,Node也不是万灵药。它擅长解决某些问题,也方便了我们。同样,在某些方面,也是它的缺点,比如:计算密集型应用。希望大家在使用Node开发之前能有更合理的考虑,在编程中获得更多的乐趣。