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 在各个浏览器中执行的耐性
Apr 06 Javascript
jquery的ajaxSubmit()异步上传图片并保存表单数据演示代码
Jun 04 Javascript
用JS将搜索的关键字高亮显示实现代码
Nov 08 Javascript
Angular使用ng-messages与PHP进行表单数据验证
Dec 28 Javascript
基于react框架使用的一些细节要点的思考
May 31 Javascript
[js高手之路]寄生组合式继承的优势详解
Aug 28 Javascript
分析JS单线程异步io回调的特性
Dec 01 Javascript
JS获取指定月份的天数两种实现方法
Jun 22 Javascript
layer弹出子iframe层父子页面传值的实现方法
Nov 22 Javascript
使用Element的InfiniteScroll 无限滚动组件报错的解决
Jul 27 Javascript
在vue中给后台接口传的值为数组的格式代码
Nov 12 Javascript
关于Vue Router的10条高级技巧总结
May 06 Vue.js
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远程连接MYSQL数据库非常慢的解决方法
2008/07/05 PHP
同台服务器使用缓存APC效率高于Memcached的演示代码
2010/02/16 PHP
遍历指定目录下的所有目录和文件的php代码
2011/11/27 PHP
调整PHP的性能
2013/10/30 PHP
PHP图像处理之使用imagecolorallocate()函数设置颜色例子
2014/11/19 PHP
PHP魔术方法使用方法汇总
2016/02/14 PHP
php 修改上传文件大小限制实例详解
2016/10/23 PHP
yii2多图上传组件的使用教程
2018/05/10 PHP
js 数据类型转换总结笔记
2011/01/17 Javascript
JS保存、读取、换行、转Json报错处理方法
2013/06/14 Javascript
JavaScript对象的property属性详解
2014/04/01 Javascript
js实现可折叠展开的手风琴菜单效果
2015/09/07 Javascript
pc加载更多功能和移动端下拉刷新加载数据
2016/11/07 Javascript
bootstrap——bootstrapTable实现隐藏列的示例
2017/01/14 Javascript
WebPack基础知识详解
2017/01/16 Javascript
基于JS实现二维码图片固定在右下角某处并跟随滚动条滚动
2017/02/08 Javascript
Js apply方法详解
2017/02/16 Javascript
JavaScript数据结构中栈的应用之表达式求值问题详解
2017/04/11 Javascript
js封装成插件_Canvas统计图插件编写实例
2017/09/12 Javascript
Vue拖拽组件开发实例详解
2018/05/11 Javascript
Javascript 对象(object)合并操作实例分析
2019/07/30 Javascript
node.js处理前端提交的GET请求
2019/08/30 Javascript
基于Angular 8和Bootstrap 4实现动态主题切换的示例代码
2020/02/11 Javascript
vue实现简单加法计算器
2020/10/22 Javascript
vue+element_ui上传文件,并传递额外参数操作
2020/12/05 Vue.js
js实现简单的倒计时
2021/01/28 Javascript
用pandas按列合并两个文件的实例
2018/04/12 Python
Django中提供的6种缓存方式详解
2019/08/05 Python
在Python中使用filter去除列表中值为假及空字符串的例子
2019/11/18 Python
PyTorch-GPU加速实例
2020/06/23 Python
希尔顿酒店中国网站:Hilton中国
2017/03/11 全球购物
新春联欢会主持词
2014/03/24 职场文书
政法干警核心价值观心得体会
2014/09/11 职场文书
法人授权委托书公证范本
2014/09/14 职场文书
二手车转让协议书
2015/01/29 职场文书
一年级语文教学随笔
2015/08/14 职场文书