node.js的事件机制


Posted in Javascript onFebruary 08, 2017

首先, 补充下对node 的理解:

nodeJs 是一个单进程单线程应用程序, 但是通过事件和回调支持并发, 所以性能非常高~

那么什么是单进程单线程呢~(写给语文跟我一样不好的小伙伴)

我们来看下单进程和多进程的区别:

1.  多进程的优势在于任务的独立性,比如某个任务单独作为一个进程的话,崩溃只影响自己的服务,其他任务不受影响.如果是多个任务在同一个进程内部利用多个线程进行处理,某个线程发生了未处理的异常的话,会导致整个进程完蛋,所有的任务跟着遭殃

2.  从资源分配上来说,多进程方案比多线程方案更加灵活和自由

3. 不过任务间的通信方面多进程要比多线程复杂些,编一个好的多进程通信方案要比多线程间的通信方案困难多了(小伙伴们注意区分进程和线程哟~)

以web server为例的话,比如我的服务器上架设了三个网站,如果是用一个进程管理的话, 网站A遭受攻击死掉了,意味着另外两个网站会出现同样的现象. 如果是分开独立的进程的话,三个网站互不影响

具体来分呢, 单进程对比多进程有什么优点呢:

1)  初期实现起来比较简单快速, 而且不用考虑进程间通信的工作量

2) 单一性使得部署和运营比较简单(这还用说  / 白眼ing)

3) 内存占用少, 不过呢, 现在内存很廉价, 但是一分钱也是钱呀!

4) 进程内部通信效率比IPC/scoket(多进程数据通讯的终端)等要高效,  我一嗓子你就听见了, 就不用费力气装个电话了

当然, 肯定优缺点!不然花那么多钱开多进程的人也太蠢了 ~

单进程对比多进程的缺点~

1) 中后期随着业务逻辑的复杂化和需求的增加,这个单进程会变得臃肿, 难以维护。 一个任务分解成多个进程会使单个进程的逻辑简单,而不容易出错

2) 同进程内模块间是强依赖关系,需要在一起编译相互的影响也比较大。 这相对于多进程间通信来说, 耦合度较大(不符合高内聚低耦合的伟大思想), 不利于多团队并行开发。 多进程更便于多语言的协作开发。

3)任何模块的崩溃都将导致整个进程的失效,多进程模式更加稳定健壮,业务处理程序隔离运行, 一个go home不会影响其他(你敢崩我也崩);

4) 性能问题: 如果不支持进程间数据通讯的话,单进程的容量是受限的, 这个性能瓶颈对于支持群组类服务的尤其需要考虑。多进程部署极其灵活,可以扩充机器数量来提高系统处理性能,还可以从硬件上避免单点故障。(一个人承受不来)

5) 单进程中多线程难调试( 一枪开出去, 一群人倒了, 我还得检查一下谁中枪了才能给你debug)

举个小栗子

你有一个对象, 对象特别挑食, 但是对象只喜欢一种菜, 你每天做给她吃。

这就是个单进程单线程的模型,  如果你做的不好吃了, 对象不吃了。

但是我有一个对象, 她喜欢吃10种菜, 我每天端过去10份, 哪天其中某一份醋放多了, 对象说真难吃, 今天不吃了。这就是单进程多线程的模型。一个菜不好吃导致对象不吃了(全部线程崩掉)

..  如果我有两个对象..  每个对象喜欢吃一种菜

ok,  一个对象觉得好吃, 吃的脸圆圆的三下巴, 一个觉得不好吃常年不吃, 骨瘦如柴。

这就是多进程单线程互不影响的模型.. 多进程多线程我就不举栗了 ~

说到这里, 小伙伴有没有对单进程单线程有一些理解呢。nodeJs 就是单进程单线程的应用程序, 进程间互不影响, 绑定多个事件可以同时触发~  不用等你完了我再有动作, 所以nodeJs性能很高。

nodeJs 单线程类似进入一个while(true ) 的事件循环, 知道没有事件观察者的时候退出(每绑定一个事件, 就生成一个事件观察者), 当有事件发生的时候, 就会调用该事件的回调函数。

事件驱动程序

nodeJs 使用事件驱动模型(稍后说), 当web server 接收到请求时, 就把它关闭然后进行处理, 然后去服务下一个web 请求。可以理解成我触发事件, 就先关闭这个事件驱动, 然后处理, 我觉得是在防止二次触发~ 造成不正确的负载和意料之外的结果,这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)

可能有的小伙伴会问了, 什么是 事件驱动模型呢~ 

其实在了解事件驱动之前, 我们可以先看一下事件驱动的三大要素:

1) 事件源:  谁来接受外部事件

2) 侦听器:  能够接收事件源通知的对象

3) 事件处理程序:  用于处理事件

好, 包含以上三点的就是一个完整的事件驱动程序。

举个栗子

如果有一天你走在路上一不小心被天上掉下来的花瓶砸到了,并且晕死了过去。那么整个过程其实就是一个事件处理流程,而且我们可以非常方便的分析出刚才所提到的事件驱动模型中的三大要素。

1.被砸晕的这个人其实就是事件源,因为他是能够接受到外部的事件的源体。

2.侦听器就是这个人的大脑神经,因为它会感知到疼痛。

3.事件处理就是这个人晕死了过去。

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

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

说了那么多, 事件绑定怎么写呢。

在node 里, 有个事件模块 events,  我们可以通过实例化的events 对象 来绑定事件。

上代码:

var event = require('events'); // 引入事件模块
var eventObj = new event(); // 实例化一个事件对象
eventObj.on('起床', function() { // 绑定事件和事件回调
console.log('洗脸刷牙');

});
eventObj.emit('起床'); // 触发事件的方法

结果是符合预期的。

但是有一点需要注意哦, 当你想移除事件的时候, 直接eventObj.removeListener(‘起床')

然后各种报错~

其实正确的移除事件的方法是这样的~

上代码:

var event = require('events'); // 引入事件模块
var eventObj = new event(); // 实例化一个事件对象
function getUp() {
console.log('洗脸刷牙');
}
eventObj.on('起床', getUp);
eventObj.emit('起床');
eventObj.removeListener('起床', getUp);
eventObj.emit('起床');

成功移除事件~

node 还提供了只触发单次事件的方法~

eventObj.once(‘起床', getUp)

还有移除全部事件呀~

eventObj.removeAllListeners(getUp), 像我这样指定了getUp的事件, 则移除所有触发该事件的监听器。

eventObj.setMaxListeners(n)  参数是一个数字, 因为node默认了绑定事件最多10个, 10个以上的时候会警告。 如果不想被警告就设置最大监听器个数咯~

eventObj.listeners(even)  返回指定事件的监听器数组

eventObj.emit(getUp, [arg1], [arg2], [...])

按照参数的顺序执行事件,  返回值是true或者false。有此监听事件就返回true。

不知道小伙伴们有没有疑惑,  我明明已经把events 模块加载过来了, 为什么还要实例化才能用呢~ 

大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。

为什么要这样做呢?原因有两点:

首先,具有某个实体功能的对象实现事件符合语义(可以自己命名了啊喂(#`O′) ), 事件的监听和发射都应该是一个对象的方法。

其次 JavaScript 的对象机制是基于原型的, 支持部分多重继承,继承 EventEmitter不会打乱对象原有的继承关系。

Node 应用程序是如何工作的?

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

接下来让我们来重新看下前面的实例,创建一个 input.txt ,文件内容如下:

123456123123

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

var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
 if (err){
 console.log(err.stack);
 return;
 }
 console.log(data.toString());});
console.log("程序执行完毕");

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

如果没发生错误,readFile 跳过 err 对象的输出,文件内容就通过回调函数输出。

执行以上代码,执行结果如下:

123456123123

接下来我们删除 input.txt 文件,执行结果如下所示:

程序执行完毕Error: ENOENT, open 'input.txt'

因为文件 input.txt 不存在,所以输出了错误信息。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
动态加载图片路径 保持JavaScript控件的相对独立性
Sep 06 Javascript
jquery ajax学习笔记2 使用XMLHttpRequest对象的responseXML
Oct 16 Javascript
JavaScript作用域与作用域链深入解析
Dec 06 Javascript
jquery自动填充勾选框即把勾选框打上true
Mar 24 Javascript
jquery实现勾选复选框触发事件给input赋值
Feb 01 Javascript
js上传图片及预览功能实例分析
Apr 24 Javascript
jQuery实现的网页竖向菜单效果代码
Aug 26 Javascript
微信小程序实现滚动消息通知
Feb 02 Javascript
微信小程序开发的基本流程步骤
Jan 31 Javascript
微信小程序单选框自定义赋值
May 26 Javascript
详解Vue Cli浏览器兼容性实践
Jun 08 Javascript
React更新渲染原理深入分析
Dec 24 Javascript
jQuery多选框选择数量限制方法
Feb 08 #Javascript
Node.js连接MongoDB数据库产生的问题
Feb 08 #Javascript
简单实现bootstrap选项卡效果
Feb 08 #Javascript
Bootstrap导航条学习使用(一)
Feb 08 #Javascript
Vue过滤器的用法和自定义过滤器使用
Feb 08 #Javascript
Javascript中的神器——Promise
Feb 08 #Javascript
jquery获取下拉框中的循环值
Feb 08 #Javascript
You might like
修改php.ini不生效问题解决方法(上传大于8M的文件)
2013/06/14 PHP
thinkphp在模型中自动完成session赋值示例代码
2014/09/09 PHP
javascript some()函数用法详解
2014/11/13 PHP
thinkphp3.0输出重复两次的解决方法
2014/12/19 PHP
PHP IDE phpstorm 常用快捷键
2015/05/18 PHP
php微信开发接入
2016/08/27 PHP
php简单截取字符串代码示例
2016/10/19 PHP
PHP架构及原理知识点详解
2019/12/22 PHP
随机显示经典句子或诗歌的javascript脚本
2007/08/04 Javascript
前端面试题及答案整理(二)
2016/08/26 Javascript
js编写的treeview使用方法
2016/11/11 Javascript
jQuery内存泄露解决办法
2016/12/13 Javascript
javascript数组去重方法分析
2016/12/15 Javascript
vue iview组件表格 render函数的使用方法详解
2018/03/15 Javascript
redux中间件之redux-thunk的具体使用
2018/04/17 Javascript
element-ui中的select下拉列表设置默认值方法
2018/08/24 Javascript
Vue2.x通用编辑组件的封装及应用详解
2019/05/28 Javascript
vue视频播放暂停代码
2019/11/08 Javascript
如何在Node和浏览器控制台中打印彩色文字
2020/01/09 Javascript
Python调用C语言开发的共享库方法实例
2015/03/18 Python
Python实时获取cmd的输出
2015/12/13 Python
Python基于Socket实现的简单聊天程序示例
2017/08/05 Python
Django使用paginator插件实现翻页功能的实例
2018/10/24 Python
对python 多线程中的守护线程与join的用法详解
2019/02/18 Python
Python操作excel的方法总结(xlrd、xlwt、openpyxl)
2019/09/02 Python
python脚本之一键移动自定格式文件方法实例
2019/09/02 Python
opencv python 图片读取与显示图片窗口未响应问题的解决
2020/04/24 Python
如何用python批量调整视频声音
2020/12/22 Python
python regex库实例用法总结
2021/01/03 Python
Zooplus葡萄牙:欧洲领先的网上宠物商店
2018/07/01 全球购物
英国助听器购物网站:Hearing Direct
2018/08/21 全球购物
JDO的含义
2012/11/17 面试题
中餐厅主管的职责范文
2014/02/04 职场文书
公司优秀员工获奖感言
2014/08/14 职场文书
美容院员工规章制度
2015/08/05 职场文书
2016年安全月活动总结
2016/04/06 职场文书