Node.js之eventproxy详解
安装
npm install eventproxy --save
调用
var EventProxy = require('eventproxy');
异步协作
多类型异步协作
此处以页面渲染为场景,渲染页面需要模版、数据。假设都需要异步读取。
var EventProxy = require('eventproxy');
//获取EventProxy实例
var ep = new EventProxy();
ep.all('tpl', 'data', function(tpl, data){//or ep.all(['tpl', 'data'], function(tpl, data{}))
//在所有指定的事件触发后, 将会被调用执行
//参数对应各自的事件名
});
fs.readFile('template.tpl', 'utf-8', function(err, content){
ep.emit('tpl', content);
});
db.get('sql', function(err, content){
ep.emit('data', result);
});
all
方法将handler注册到事件组合上。当注册的所有事件均触发后,将会调用handler执行,每个事件传递的数据,将会依照事件名顺序,传入handler作为参数。
快速创建
EventProxy提供了create
静态方法,可以快速完成注册all事件。
var ep_create = EventProxy.create('tpl', 'data', function(tpl, data){
//TODO
});
以上方法等效于
var ep = new EventProxy();
ep.all('tpl', 'data', function(tpl, data){
//TODO
});
重复异步协作
此处以读取目录下所有文件为例,在异步操作中,我们需要在所有异步调用结束后,执行某些操作。
var ep = new EventProxy();
ep.after('got_file', files.length, function(list){
//在所有文件的异步执行结束后将被执行
//所有文件的内容都存在list数组中
});
for(var i = 0; i<files.length; i++){
fs.readFile(files[i], 'utf-8', function(err, content){
//触发结果事件
ep.emit('got_file', content);
})
}
after
方法适合重复的操作,比如爬10个网站,读10个文件,调用5次数据库等。将handler注册到N次相同事件的触发上。达到指定的触发数,handler将会被调用执行,每次触发的数据,将会按触发顺序,存为数组作为参数传入。
持续型异步协作
此处以股票为例,数据和模版都是异步获取,但是数据会持续刷新,视图会需要重新刷新。
var ep = new EventProxy();
ep.tail('tpl', 'data', function(tpl, data){
//待所有指定的时间都触发后,将第一次回调
//以后再出发其中之一的时间,都会回调
});
fs.readFile('template.tpl', 'utf-8', function(err, content){
ep.emit('tpl', content);
});
setInterval(function(){
db.get('sql', function(err, result){
ep.emit('data', result);
});
}, 2000);
tail
与all
方法比较类似, 都是注册到事件组合上。不同在于,指定事件都触发之后,如果事件依旧持续触发,将会在每次触发时调用handler,像一条尾巴一样。
基本事件
通过事件实现异步协作是EventProxy的主要亮点。除此之外,它还是一个基本的事件库。携带如下基本API
on/addListener
绑定事件监听器emit
触发事件once
绑定只执行一次的事件监听器removeListener
移除事件监听器removeAllListeners
移除单个事件或所有事件的监听器
异常处理
在异步方法中,实际上,异常处理需要占用一定比例的经历。在过去一段时间内,我们都是通过额外添加error
事件来进行处理的,代码大致如下:
exports.getContent = function(callback){
var ep = new EventProxy();
ep.all('tpl', 'data', function(tpl, data){
//成功回调
callback(null, {
template: tpl,
data: data
});
});
//监听error事件
ep.bind('error', function(err){
//卸掉所有的handler
ep.unbind();
//异常回调
callback(err);
});
fs.readFile('template.tpl', 'utf-8', function(err, content){
if(err){
//一旦异常发生,一律交给error事件的handler处理
return ep.emit('error', err);
}
ep.emit('tpl', content);
});
db.get('sql', function(err, result){
if(err){
//一旦异常发生,一律交给error事件的handler处理
return ep.emit('error', err);
}
ep.emit('data', result);
});
};
代码量因为异常的处理,一下子上去了很多。在这里EventProxy经过很多实践后,给我们提供了优化了的错误处理方案。
exports.getContent = function(callback){
var ep = new EventProxy();
ep.all('tpl', 'data', function(tpl, data){
//成功回调
callback(null, {
template: tpl,
data: data
});
});
//添加error handler
ep.fail(callback);
fs.readFile('template.tpl', 'utf-8', ep.done('tpl'));
db.get('sql', ep.done('data'));
};
上述代码优化之后,代码量明显降低。下面让我们来讨论一下fail
和done
方法。
fail方法
ep.fail(callback);
//实际上为
ep.fail(function(err){
callback(err);
});
//等价于
ep.bind('error', function(err){
//卸载掉所有handler
ep.unbind();
//异常回调
callback(err);
});
fail
方法监听了error
事件,默认处理卸掉所有handler,并调用回调函数。
throw方法
throw
是ep.emit('error', err)
的简写。
var err = new Error();
ep.throw(err);
//实际上
ep.emit('error', err);
done方法
ep.done('tpl');
//等价于
function(err, content){
if(err){
//一旦异常发生,一律交给error事件的handler处理
return ep.emit('error', err);
}
ep.emit('tpl', content);
}
在Node的最佳实践中,回调函数第一个参数一定是一个error
对象。检测到异常后,将会触发error
事件。剩下的参数,将触发事件,传递给对应handler处理。
done方法也接受回调函数
done
方法除了接受事件名外,还接受回调函数。如果是函数时,它将剔除第一个error对象(此时应为null
),后剩余的参数,传递给该回调函数作为参数。该回调函数无需要考虑异常处理。
ep.done(function(content){
//这里无需考虑异常
//手动emit
ep.emit('event', content);
});
group
fail
除了用于协助all
方法完成外,也能协助after
中的异常处理。另外在after
的回调函数中,结果顺序是与用户emit
的顺序有关。为了满足返回数据按发起异步调用的顺序排列,EventProxy
提供了group
方法。
var ep = new EventProxy();
ep.after('got_file', files.length, function(list){
//在所有文件的异步执行结束后被执行
//所有文件的内容都存在list数组中,按顺序排列
});
for(var i = 0; i < files.length; i++){
fs.readFile(files[i], 'utf-8', ep.group('got_file'));
}
group
秉承done
函数的设计,它包含异常的传递。同时它还隐含了对返回数据进行编号,在结束时,按顺序返回。
ep.group('got_file');
//约等价于
function(err, data){
if(err){
return ep.emit('error', err);
}
ep.emit('got_file', data);
};
当回调函数的数据还需要进行加工时,可以给group
带上回调函数,只要在操作后将数据返回即可:
ep.group('got_file', function(data){
return data;
});
注意事项
- 请勿使用
all
作为业务的事件名。该事件名为保留事件。 - 异常处理部分,请遵循Node的最佳实践(回调函数首个参数为异常传递位)。
上述内容为学习笔记,选自https://github.com/JacksonTian/eventproxy
欢迎转载,转载请注明出处
update by 2017/7/25 15:02
该部分完结
by 一枝猪
Node.js之eventproxy详解的更多相关文章
- 《Node.js开发实战详解》学习笔记
<Node.js开发实战详解>学习笔记 ——持续更新中 一.NodeJS设计模式 1 . 单例模式 顾名思义,单例就是保证一个类只有一个实例,实现的方法是,先判断实例是否存在,如果存在则直 ...
- node.js的npm详解
一.什么是npm呢 npm(Node Package Manager,node包管理器)是node的包管理器,他允许开发人员在node.js应用程序中创建,共享并重用模块.模块就是可以在不同的项目中重 ...
- Node.js HTTP 使用详解
对于初学者有没有发觉在查看Node.js官方API的时候非常简单,只有几个洋文描述两下子,没了,我第一次一口气看完所以API后,对于第一个示例都有些懵,特别是参数里的request和response, ...
- Node.js中Async详解:流程控制
安装 npm install async --save 地址 https://github.com/caolan/async Async的内容主要分为三部分 流程控制: 简化九种常见的流程的处理 集合 ...
- Node.js + Express中间件详解
使用中间件 Express是一种路由和中间件Web框架,它具有自己的最小功能:Express应用程序本质上是一系列中间件函数调用. 中间件函数是可以访问请求对象 (req),响应对象(res)以及应用 ...
- 阿里云ECS服务器部署Node.js项目全过程详解
本文详细介绍如何部署NodeJS项目到阿里云ECS上,以及本人在部署过程中所遇到的问题.坑点和解决办法,可以说是全网最全最详细的教程了.同时讲解了如何申请阿里云免费SSL证书,以及一台ECS服务器配置 ...
- ES6,ES2105核心功能一览,js新特性详解
ES6,ES2105核心功能一览,js新特性详解 过去几年 JavaScript 发生了很大的变化.ES6(ECMAScript 6.ES2105)是 JavaScript 语言的新标准,2015 年 ...
- Js apply 方法 详解
Js apply方法详解 我在一开始看到JavaScript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...
- Js apply()使用详解
Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...
随机推荐
- 由.Net类库提供的农历计算
由.Net类库提供的农历计算(C#农历) 2007-11-21 12:47:00 标签:.Net 类库 农历计算 C#农历 休闲 ...
- NYOJ--1276--机器设备(河南省第九届省赛,简单的bfs)
机器设备 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 Alpha 公司设计出一种节能的机器设备.它的内部结构是由 N 个齿轮组成.整个机器设备有 一个驱动齿轮,当 ...
- AKOJ -- 1529 -- 寻找最大数
1529: 寻找最大数 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 107 Solved: 53 上一题SubmitStatus标签打分编辑题目信 ...
- JDK、Eclipse、Myeclipse、Tomcat等各种软件的版本详解(写给对版本和兼容性问题焦头烂额的你)
这篇文章我们来探讨一下关于JDK.Eclipse.Myeclipse.Tomcat的版本问题.一.关于版本的几个概念1.32位和64位两个版本: 简言之,64位的操作系统支持识别4G以上的内存条 ...
- .net core 2.0学习笔记(二):Hello World & 进阶
官网已经有一个.net core的入手教程(https://www.microsoft.com/net/core#windowscmd),但这个教程完全没有顾及全宇宙第一IDE的感受.今天就跟大家体验 ...
- UNIX 技巧: UNIX 高手的另外 10 个习惯
让我们面对现实吧:坏习惯很难改变.但是您已经熟悉的习惯可能更难克服.有时,重新审视某些事情可能让您遇到“啊哈,我没想到它能做到这一点!”的时刻.在 Michael Stutz 的优秀文章“UNIX 高 ...
- DVWA笔记之三:CSRF
CSRF与XSS不同,它称为跨站请求伪造,它是利用其他页面的恶意脚本来加载访问或操作存在CSRF的漏洞的可信网站. 1.Low级别 核心代码如下: <?php if( isset( $_GET ...
- 物体自由落体动态模拟(Linear Subspace)
三维物体变形方法赋予了模拟物体的动态特性,但是随着物体模型的复杂度慢慢增加,对高质量的实时变形方法也提出了更高的要求.对于高精度的大型三维网格而言,通常会设计一个低精度的子网格,并构建子网格与原始网格 ...
- HTML的第一课
今天是第一天学习HTML,老师讲的内容不是很多,内容也比较简单.但是标签的数量很多,在做作业时十分不熟练,很多标签需要重新看它的意思.而且有很多标签在一起用的时候容易搞混.学的标签中有很多地方是通用的 ...
- .Net Framework下对Dapper二次封装迁移到.Net Core2.0遇到的问题以及对Dapper的封装介绍
今天成功把.Net Framework下使用Dapper进行封装的ORM成功迁移到.Net Core 2.0上,在迁移的过程中也遇到一些很有意思的问题,值得和大家分享一下.下面我会还原迁移的每一个过程 ...