探索node之事件循环的实现


Posted in Javascript onOctober 30, 2020

事件循环

Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。

Node.js 几乎每一个 API 都是支持回调函数的。

Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。

Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数.

进程:CPU执行任务的模块

线程:模块中的最小单元

举个通俗的例子:

cpu比作我们每个人,到饭点吃饭了。可以点很多菜(cpu中的进程):宫保鸡丁,鱼香肉丝,酸辣土豆丝。每样菜具体包含了哪些内容(cpu每个进程中的线程):宫保鸡丁(详情:黄瓜、胡萝卜、鸡肉、花生米)。而详情构成了宫保鸡丁这道菜,吃了以后不饿。就可以干活了,cpu中的进程里的线程也是同理。当线程完成自己的内容将结果返回给进程,进程返回给cpu的时候。cpu就能处理日常需求。

  • 单进程单线程:一盘炒苦瓜,里面只有苦瓜。
  • 单进程多线程:一盘宫保鸡丁,里面有黄瓜、胡萝卜、鸡肉、花生米

事件驱动程序

Node.js使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求
当这个请求完成,它被放回处理队列,当到达队列开头,这个结果就返回给用户。

这个模型非常高效可扩展性非常强,因为 webserver 一直接受请求而不等待任何读写操作。(这也称之为非阻塞式IO或者事件驱动IO)

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

探索node之事件循环的实现

整个事件驱动的流程就是这么实现的,非常简洁。有点类似于观察者模式,事件相当于一个主题(Subject),而所有注册到这个事件上的处理函数相当于观察者(Observer)。

Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下实例:

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

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

//通过程序触发事件
eventEmitter.emit('eventName')

示例:

//引入events模块
let events = require('events');

//创建eventEmitter对象
let eventEmitter = new events.EventEmitter();

//创建事件处理程序
let connectHandle = function connected() {
 console.log('连接成功');
 //触发data_received事件
 eventEmitter.emit('data_received')
}

//绑定connection事件处理程序
eventEmitter.on('connection', connectHandle);

//使用匿名函数绑定data_received事件
eventEmitter.on('data_received', function () {
 console.log('数据接收成功');
})

//触发connecttion事件
eventEmitter.emit('connection');
console.log('程序执行完毕');


// 执行结果:
// 连接成功
// 数据接收成功
// 程序执行完毕

eventEmitter.emit 是触发事件(事件请求),eventEmitter.on是绑定处理事件的处理器(事件处理),事件的请求和处理是分开的,所以是异步。

EventEmitter

node.js所有的异步I/O操作在完成时都会发送一个事件到事件队列

node.js里面的许多对象都会分发事件:一个net.Server对象会在每次有新连接时触发的一个事件,一个fs.readStream对象会在文件被打开的时候触发一个事件。所有这些产生事件的对象都是events.EventEmitter的实例

events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。

EventEmitter 对象如果在实例化时发生错误,会触发 error 事件。当添加新的监听器时,newListener 事件会触发,当监听器被移除时,removeListener 事件被触发。

简单用法

var EventEmitter = require('events').EventEmitter; 
var event = new EventEmitter(); 
event.on('some_event', function() { 
  console.log('some_event 事件触发'); 
}); 
setTimeout(function() { 
  event.emit('some_event'); 
}, 1000);

运行这段代码,1 秒后控制台输出了 ‘some_event 事件触发'。
其原理是 event 对象注册了事件 some_event 的一个监听器,
然后我们通过 setTimeout 在 1000 毫秒以后向 event 对象发送事件 some_event,此时会调用some_event 的监听器。

EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持 若干个事件监听器。

当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。

var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.on('someEvent', function(arg1, arg2) { 
  console.log('listener1', arg1, arg2); 
}); 
emitter.on('someEvent', function(arg1, arg2) { 
  console.log('listener2', arg1, arg2); 
}); 
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数'); 
//输出:
// listener1 arg1 参数 arg2 参数
// listener2 arg1 参数 arg2 参数

以上例子中,emitter 为事件 someEvent 注册了两个事件监听器,然后触发了 someEvent 事件。

运行结果中可以看到两个事件监听器回调函数被先后调用。 这就是EventEmitter最简单的用法。

EventEmitter 提供了多个属性,如 on 和 emit。on 函数用于绑定事件函数,emit 属性用于触发一个事件。、

EventEmitter属性

探索node之事件循环的实现

测试

/*
 * @Author: angula
 * @Date: 2020-09-21 22:29:18
 * @LastEditTime: 2020-09-22 11:27:56
 * @FilePath: \JS\Github-前端知识总结仓库\studySummary\Node.js学习笔记\事件循环\index2.js
 */
let events = require('events');
let eventEmitter = new events.EventEmitter();

// 监听器1
let listener1 = function listener1() {
 console.log('监听器listener1启动。。。');
}

// 监听器2
let listener2 = function listener2() {
 console.log('监听器listener2启动。。。');
}

// 绑定connection事件,处理函数为listener1
eventEmitter.addListener('connection', listener1);
// 绑定connection事件,处理函数为listener2
eventEmitter.on('connection', listener2);


//类,返回监听器的数量

let eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + '个监听器监听连接事件。');


//处理connection事件
eventEmitter.emit('connection');

// 移除绑定的listener1
eventEmitter.removeListener('connection', listener1);
console.log('listener1不再受监听');

//触发连接事件
eventEmitter.emit('connection');

eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + '个监听器连接事件');

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

执行结果:

探索node之事件循环的实现

到此这篇关于探索node之事件循环的实现的文章就介绍到这了,更多相关node 事件循环内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
javascript 日历提醒系统( 兼容所有浏览器 )
Apr 07 Javascript
js querySelector和getElementById通过id获取元素的区别
Apr 20 Javascript
js 调用本地exe的例子(支持IE内核的浏览器)
Dec 26 Javascript
jQuery输入城市查看地图使用介绍
May 08 Javascript
只需一行代码,轻松实现一个在线编辑器
Nov 12 Javascript
JavaScript实现可拖拽的拖动层Div实例
Aug 05 Javascript
js实现滚动条滚动到页面底部继续加载
Dec 19 Javascript
实用jquery操作表单元素的简单代码
Jul 04 Javascript
jQuery插件HighCharts实现的2D面积图效果示例【附demo源码下载】
Mar 15 Javascript
对vue下点击事件传参和不传参的区别详解
Sep 15 Javascript
JavaScript canvas仿代码流瀑布
Feb 10 Javascript
jquery实现点击左右按钮切换图片
Jan 27 jQuery
使用TS来编写express服务器的方法步骤
Oct 29 #Javascript
微信小程序将页面按钮悬浮固定在底部的实现代码
Oct 29 #Javascript
vue3.0搭配.net core实现文件上传组件
Oct 29 #Javascript
使用jQuery实现购物车
Oct 29 #jQuery
ant design中upload组件上传大文件,显示进度条进度的实例
Oct 29 #Javascript
react使用antd表单赋值,用于修改弹框的操作
Oct 29 #Javascript
node.js爬虫框架node-crawler初体验
Oct 29 #Javascript
You might like
PHP可变函数学习小结
2015/11/29 PHP
PHP自定义错误用法示例
2016/09/28 PHP
PHP文件后缀不强制为.php方法
2019/03/31 PHP
关于JS判断图片是否加载完成且获取图片宽度的方法
2013/04/09 Javascript
javascript圆盘抽奖程序实现原理和完整代码例子
2014/06/03 Javascript
通过js获取上传的图片信息(临时保存路径,名称,大小)然后通过ajax传递给后端的方法
2015/10/01 Javascript
基于JavaScript实现右键菜单和拖拽功能
2016/11/28 Javascript
完全深入学习Bootstrap表单
2016/11/28 Javascript
JS实现微信弹出搜索框 多条件查询功能
2016/12/13 Javascript
jquery 键盘事件的使用方法详解
2017/09/13 jQuery
基于express中路由规则及获取请求参数的方法
2018/03/12 Javascript
解决Vue中 父子传值 数据丢失问题
2019/08/27 Javascript
layer 关闭指定弹出层的例子
2019/09/25 Javascript
vue实现tab栏点击高亮效果
2020/08/19 Javascript
[04:47]DOTA2-潍坊风行电子俱乐部探秘
2014/08/08 DOTA
python目录与文件名操作例子
2016/08/28 Python
Python中的日期时间处理详解
2016/11/17 Python
python分割列表(list)的方法示例
2017/05/07 Python
Python实现的线性回归算法示例【附csv文件下载】
2018/12/29 Python
Python 中 -m 的典型用法、原理解析与发展演变
2019/11/11 Python
python3爬虫中多线程进行解锁操作实例
2020/11/25 Python
python xlsxwriter模块的使用
2020/12/24 Python
怎样声明接口
2014/09/19 面试题
中学家长会邀请函
2014/01/17 职场文书
应届电子商务毕业自荐书范文
2014/02/11 职场文书
《天安门广场》教学反思
2014/04/23 职场文书
《恐龙》教学反思
2014/04/27 职场文书
学校学雷锋活动总结
2014/06/26 职场文书
祖国在我心中演讲稿200字
2014/08/28 职场文书
大学生实习证明范本
2014/09/19 职场文书
付款委托书范本
2014/10/05 职场文书
2014年银行个人工作总结
2014/12/05 职场文书
2015年学校禁毒工作总结
2015/05/27 职场文书
老舍《猫》教学反思
2016/02/17 职场文书
python生成可执行exe控制Microsip自动填写号码并拨打功能
2021/06/21 Python
spring boot实现文件上传
2022/08/14 Java/Android