node.js学习笔记(三)——事件循环

  要理解事件循环,首先要理解事件驱动编程(Event Driven Programming)。它出现在1960年。如今,事件驱动编程在UI编程中大量使用。JavaScript的一个主要用途是与DOM交互,所以使用基于事件的API是很自然的。简单地定义:事件驱动编程通过事件或状态的变化来进行应用程序的流程控制。一般通过事件监听实现,一旦事件被检测到(即状态改变)则调用相应的回调函数。听起来很熟悉?其实这就是node.js事件循环的基本工作原理。如果你熟悉客户端JavaScript的开发,想一想那些.on*()方法,如element.onclick(),他们用来与DOM元素相结合,传递用户交互。这个工作模式允许在单个实例上触发多个事件。Node.js通过EventEmitter(事件发生器)触发这种模式,如在服务器端的Socket和 “http”模块中,可以从一个单一实例触发一种或一种以上的状态改变。

  js是单线程,对于阻塞操作,js会封装参数和回调函数,交给底层去处理,也就是io线程池。线程池处理完毕会放到一个类似队列里面,然后node的事件循环线程会去获取这个队列的数据,执行回调。也就是说使用事件驱动模型的node.js,在当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)。

   在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。

  如上图所示,每个异步函数执行结束后,都会在事件队列中追加一个事件(同时保存一些必要参数)。事件轮询下一次循环便可取出事件,然后会调用异步方法对应的回调函数(参数)。这样一来,nodejs便能保证开发者编写的每行代码(每个回调)均在主线程中执行。注意这里有一个问题,如果开发者在回调函数中调用了阻塞方法,那么整个事件轮询就会阻塞,事件队列中的事件得不到及时处理。正因为这样,node.js中的一些库方法均是异步的,也提倡用户调用异步方法。

 

  node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类(EventEmitter类会在下一笔记做分析)来绑定和监听事件,如下实例:

// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();

  绑定事件处理程序:

// 绑定事件及事件的处理程序
eventEmitter.on('eventName', eventHandler);

  触发事件:

// 触发事件
eventEmitter.emit('eventName');

 

  接下来就通过一个实例来实操一下。毕竟说得再多还不如动手试试。

  创建 demo3.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命令查看效果:

 

  

 

 

  在 node 应用程序中,执行异步操作的函数将回调函数作为最后一个参数, 回调函数接收错误对象作为第一个参数。

  下面我们再来看一个栗子。先创建一个txt文本文件,比如demo3_1.txt,文本内容如下:

this is a demo!

  再创建一个node脚本,比如叫demo3_1.js,代码如下:

//引入文件操作系统模块
var fs = require("fs");
//异步读取文件内容
fs.readFile('demo3_1.txt', function (err, data) {
       //如果在读取文件过程中发生错误,错误 err 对象就会输出错误信息。
       //如果没发生错误,readFile 跳过 err 对象的输出,文件内容就通过回调函数输出。
    if (err){
          console.log(err.stack);
          return;
    }
    console.log(data.toString());
});

console.log("程序执行完毕");  

  执行node命令查看效果:

  

 

  可以看到,脚本读取文件内容成功,所以不会报错。我们可以试着让它报错,比如把txt文件删除了,然后再来看看效果。

 

 

 

  由于文件 demo3_1.txt 不存在,所以输出了错误信息。

  上面可以看到,fs.readFile()方法的最后一个参数就是回调函数,而回调函数里面第一个参数就是回调函数接受的错误参数。

 

  关于node.js的事件循环机制,我还只是了解了点皮毛,如果有大神愿意指导,鄙人很愿意聆听(*^-^*)

转载于:https://www.cnblogs.com/slly/p/6474258.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值