深入理解Node.js 事件循环和回调函数

本文详细的介绍了Node.js 事件循环和Node.js回调函数,废话不多说了,具体看下面把。

 一、Node.js 事件循环

Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高。Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发。Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数.

1、事件驱动程序

Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。这个模型非常高效可扩展性非常强,因为web server一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)。在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。

整个事件驱动的流程就是这么实现的,非常简洁。有点类似于观察者模式,事件相当于一个主题(Subject),而所有注册到这个事件上的处理函数相当于观察者(Observer)。Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下实例:

 // 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();
以下程序绑定事件处理程序:
// 绑定事件及事件的处理程序
eventEmitter.on('eventName', eventHandler);
我们可以通过程序触发事件:
// 触发事件
eventEmitter.emit('eventName');

2、实例

创建 main.js 文件,代码如下所示:

// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();
// 创建事件处理程序
var connectHandler = function connected() {
  console.log('连接成功。');
  // 触发 data_received 事件
  eventEmitter.emit('data_received');
}
// 绑定 connection 事件处理程序
eventEmitter.on('connection', connectHandler);
// 使用匿名函数绑定 data_received 事件
eventEmitter.on('data_received', function(){
  console.log('数据接收成功。');
});
// 触发 connection 事件
eventEmitter.emit('connection');
console.log("程序执行完毕。"); 

二、Node.js 回调函数

Node.js 异步编程的直接体现就是回调。异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js 的性能,可以处理大量的并发请求。

1、阻塞代码实例

创建一个文件 test.txt ,内容如下:

Hello World!
fs.readFileSync()
fs.readFile()

创建 test.js 文件, 代码如下:

console.log('-------程序开始执行--------');
// 引入fs模块
var fs = require("fs");
//同步读取文件
var data = fs.readFileSync('test.txt','utf-8');
console.log(data.toString());
console.log('-------程序执行结束--------');

以上代码执行结果如下:

2、非阻塞代码实例

创建 test.js 文件, 代码如下:

console.log('-------程序开始执行--------');
// 引入fs模块
var fs = require("fs");
//异步读取文件
fs.readFile('test.txt','utf-8',function (err, data) {
  if (err) return console.error(err);
  console.log(data.toString());
});
console.log('-------程序执行结束--------');  

以上程序中 fs.readFile() 是异步函数用于读取文件。如果在读取文件过程中发生错误,错误 err 对象就会输出错误信息。如果没发生错误,readFile 跳过 err 对象的输出,文件内容就通过回调函数输出。

以上代码执行结果如下:
接下来我们删除 input.txt 文件,执行结果如下所示:
 以上两个实例我们了解了阻塞与非阻塞调用的不同。第一个实例在文件读取完后才执行完程序。第二个实例我们不需要等待文件读取完,这样就可以在读取文件时同时执行接下来的代码,大大提高了程序的性能。因此,阻塞按是按顺序执行的,而非阻塞是不需要按顺序的,所以如果需要处理回调函数的参数,我们就需要写在回调函数内。

三、fs.readFileSync和fs.readFile

1、s.readFileSync

语法:fs.readFileSync(filename, [encoding])

接收参数:

filename:文件路径

options:option对象,包含 encoding,编码格式,该项是可选的。

由于Node.js仅支持如下编码:utf8, ucs2, ascii, binary, base64, hex,并不支持中文GBK或GB2312之类的编码,因此如果要读写GBK或GB2312格式的文件的中文内容,必须要用额外的模块:iconv-lite。

2、fs.readFile

语法:fs.readFile(filename, [encoding], [callback(err,data)])

接收参数:

filename:文件路径

options :option对象,包含 encoding,编码格式,该项是可选的。

callback :回调,传递2个参数 异常err 和 文件内容 data

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

时间: 2016-11-01

Node.js事件循环(Event Loop)和线程池详解

Node的"事件循环"(Event Loop)是它能够处理大并发.高吞吐量的核心.这是最神奇的地方,据此Node.js基本上可以理解成"单线程",同时还允许在后台处理任意的操作.这篇文章将阐明事件循环是如何工作的,你也可以感受到它的神奇. 事件驱动编程 理解事件循环,首先要理解事件驱动编程(Event Driven Programming).它出现在1960年.如今,事件驱动编程在UI编程中大量使用.JavaScript的一个主要用途是与DOM交互,所以使用基于事件

Node.js 事件循环详解及实例

 Node.js  事件循环详解及实例 Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现. Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数. Node.js 有多个内置的事件,我们可以

我的Node.js学习之路(三)--node.js作用、回调、同步和异步代码 以及事件循环

一,node.js的作用, I/O的意义,(I/O是输入/输出的简写,如:键盘敲入文本,输入,屏幕上看到文本显示输出.鼠标移动,在屏幕上看到鼠标的移动.终端的输入,和看到的输出.等等)   node.js想解决的问题,(处理输入,输入,高并发 .如 在线游戏中可能会有上百万个游戏者,则有上百万的输入等等)(node.js适合的范畴:当应用程序需要在网络上发送和接收数据时Node.js最为适合.这可能是第三方的API,联网设备或者浏览器与服务器之间的实时通信)   并发的意义,(并发这个术语描述的

小结Node.js中非阻塞IO和事件循环

学习和使用Node.js已经有两个月,使用express结合mongoose写了一个web应用和一套RESTful web api,回过头来看Node.js官网首页对Node.js的介绍:Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.那么其中的non-blocking I/O model 意味着什么呢? 非阻塞的IO模型 首先,IO操作无疑是耗时的,当服务器

深入浅析Node.js 事件循环

Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. (来源于Javascript是单线程又是异步的,但是这种语言有个共同的特点:它们是 event-driven 的.驱动它们的 event 来自一个异构的平台.) Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现. Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件

深入浅析Node.js 事件循环、定时器和process.nextTick()

什么是事件循环 尽管JavaScript是单线程的,但通过尽可能将操作放到系统内核执行,事件循环允许Node.js执行非阻塞I/O操作. 由于现代大多数内核都是多线程的,因此它们可以处理在后台执行的多个操作. 当其中一个操作完成时,内核会告诉Node.js,以便可以将相应的回调添加到 轮询队列 中以最终执行. 我们将在本主题后面进一步详细解释. 事件循环解释 当Node.js启动时,它初始化事件循环,处理提供的输入脚本(或放入 REPL ,本文档未涉及),这可能会进行异步API调用,调度计时器或

详解node.js 事件循环

Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高. Node.js 几乎每一个 API 都是支持回调函数的. Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现. Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数. 事件驱动程序 Node.js 使用事件驱动模型,当web server接收到请

浅析Node.js非对称加密方法

前言 刚回答了SegmentFault上一个兄弟提的问题<非对称解密出错>.这个属于Node.js在安全上的应用,遇到同样问题的人应该不少,基于回答的问题,这里简单总结下. 非对称加密的理论知识,可以参考笔者前面的文章<NODEJS进阶:CRYPTO模块之理论篇>. 完整的代码可以在 <Nodejs学习笔记> 找到,也欢迎大家关注 程序猿小卡的GitHub. 加密.解密方法 在Node.js中,负责安全的模块是crypto.非对称加密中,公钥加密,私钥解密,加解密对应的

node.JS事件机制与events事件模块的使用方法详解

node.JS事件机制说明 多数 Node.js 核心 API 都是采用惯用的异步事件驱动架构,其中某些类型的对象(称为触发器)会周期性地触发命名事件来调用函数对象(监听器).例如,一个net.Server对象会在每次有新连接时触发一个事件:一个 fs.ReadStream 会在文件被打开时触发一个事件:一个 stream会在数据可读时触发事件. EventEmitter EventEmitter 类由 events 模块定义和开放的,所有能触发事件的对象都是 EventEmitter 类的实例

从Node.js事件触发器到Vue自定义事件的深入讲解

Node.js中的事件触发器所引发的思考 今天在看 Node.js 文档的时候讲到事件触发器,其中的 emit 方法让我想到了 Vue 中的自定义事件,借此我对 Vue 又有了新的理解,所以将我的理解记录下来,留作学习笔记. Node.js中的事件触发器 Node.js 为我们提供了一个事件模块:EventEmitter,我们可以用它来处理事件 const EventEmitter = require('events') const eventEmitter = new EventEmitter

跟我学Nodejs(二)--- Node.js事件模块

简介及资料 http://nodejs.org/api/events.html http://www.infoq.com/cn/articles/tyq-nodejs-event events是node.js 最重要的模块,events模块只提供了一个对象events.EventEmitter,EventEmitter 的核心是事件发射与事件监听器. Node.js中大部分的模块,都继承自Event模块. 与DOM树上事件不同,不存在事件冒泡.逐层捕获等行为. EventEmitter 支持若干