资讯专栏INFORMATION COLUMN

认识 Node .js

I_Am / 3001人阅读

摘要:服务器每收到一条请求,都会用新的和对象触发请求回调函数。在调用完请求回调函数之后,就要由你负责用方法结束响应。

前言

本文将介绍Node.js的一些基本概念,包含它的历史,特性和简单的使用等。如果你有过服务端的编程经验,那么你将能很快熟悉它。

Node.js是什么

这是Node.js官网上对其的定义,就是说,Node.js是一个javascript运行平台,该平台基于chrome v8 引擎。V8让Node.js在性能上得到了巨大的提升,因为它去掉了中间环节,执行的不是字节码,用的也不是解释器,而是直接编译成了本地机器码。(注意:v8 5.9 发布后,Ignition 字节码解释器将默认启动,v8 又回到了字节码的怀抱,具体请参阅:https://cnodejs.org/topic/590...)

Node.js带来的好处

对一名前端而言,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 * FORM work", function (data) {
    console.log(data)
  }
)

这段代码做了些I/O操作,并且在所有数据回来之前,这个进程并不会被阻塞。在Node中,I/O几乎总是在主事件轮询之外进行,使得服务器可以一直处于高效并且随时能够做出响应的状态,就像NGINX(带有异步I/O的事件轮询的一种http服务器)一样。这样进程不会受I/O限制,因为I/O延迟不会拖垮服务器。因此一些在服务器上曾经是重量级的操作,在Node服务器上仍然可以是轻量级的。

dirt程序

Node所针对的应用程序有一个专门的简称:DIRT。它表示数据密集型实时(data-intensive real-time)程序。上面已经提到,Node自身在I/O上非常轻量,能在处理大量请求时保持很多开放的连接,并且只占用一小部分内存,所以,它特别擅长处理数据密集型实时应用。比如在线文档协作、对临近公交车的实时精确定位,以及多人在线游戏等。

简单的例子

接下来我们先看一些简单的例子。

文件操作
var fs = require("fs")

fs.readFile("./package.json", "utf8", function (er, data) {
  console.log(data)
})

这段程序是要从硬盘里读取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 的文件,代码如下:

var http = require("http")

http.createServer(function(req, res) {
  res.writeHead(200, {"Content-Type": "text/html"})
  res.write("

Node.js

") res.end("

Hello World

") }).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("

Hello World

")结束了一次响应。

在终端中运行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开发之前,多一些合理的考虑,多一份编程的快乐。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95900.html

相关文章

  • 认识node核心模块--从Buffer、Stream到fs

    摘要:端输入数据到端,对就是输入流,得到的对象就是可读流对就是输出端得到的对象是可写流。在中,这四种流都是的实例,它们都有事件,可读流具有监听数据到来的事件等,可写流则具有监听数据已传给低层系统的事件等,和都同时实现了和的事件和接口。 原文地址在我的博客 node中的Buffer和Stream会给刚接触Node的前端工程师们带来困惑,原因是前端并没有类似概念(or 有我们也没意识到)。然而,...

    TANKING 评论0 收藏0
  • 还不打算去认识一下webpack?

    摘要:前言随我来去看看为时未晚第一版较浅显的知识懂得可忽略本文方向安装起步搭建运行粗略代过对于资源的管理对于输出的管理举例介绍本地开发基础服务热更新模块热替换初步认识初步构建新建一个文件并进入更目录是命令初始一个文件表示跳过询问步骤安装 前言 随我来,去看看webpack!(为时未晚)============》第一版(较浅显的知识,懂得可忽略本文) 方向 安装,起步搭建运行. (粗略代...

    Tony_Zby 评论0 收藏0
  • 认识React

    摘要:认识准备写有两种方式通过通过写起来感觉会更方便,但就需要用进行编译了。组件的两个重要对象就是一个组件模板的数据对象。当一个组件进行了登录之后,应该通知其他需要更新登录信息的组件。 认识React 准备 babel-cli 写 React 有两种方式: 通过 jsx 通过 js jsx 写起来感觉会更方便,但就需要用babel进行编译了。 用babel编译 React 的 jsx 有...

    noONE 评论0 收藏0
  • 从安装认识Angular 2

    摘要:首先,要确认安装了,并且创建了目录并执行初始化。想必看见上面的那么多包会一脸懵逼,没关系,我第一眼看见这些的那刻,和你现在的表情一样,下面在适当的时候我会逐个解释的,你只需要相信我上面的包都是跑所必须的,缺一不可。 关于介绍,只说一句:Angular 2是一个强大、全面、庞大的MVVM框架。 安装 安装,也算是一个坎,因为你需要安装一大堆东西,却不知道每个东西是做什么的,尽管有Angu...

    xietao3 评论0 收藏0
  • 染陌的 2017 年度总结

    摘要:写在前面看到了死月佳楠等朋友都写了关于的年度总结,总觉得自己也应该写点东西来回首过去的一年,顺便展望一下未来的年。在这份榜单上排在的位置,年也希望更上一层楼。年底跟女朋友结束了四年的恋爱长跑,成功领证。 写在前面 看到了死月、doodlewind、佳楠等朋友都写了关于 2017 的年度总结,总觉得自己也应该写点东西来回首过去的一年,顺便展望一下未来的 2018 年。 由于之前忙于撰写《...

    AdolphLWQ 评论0 收藏0

发表评论

0条评论

I_Am

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<