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);

tailall方法比较类似, 都是注册到事件组合上。不同在于,指定事件都触发之后,如果事件依旧持续触发,将会在每次触发时调用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'));
};

上述代码优化之后,代码量明显降低。下面让我们来讨论一下faildone方法。

fail方法

ep.fail(callback);
//实际上为
ep.fail(function(err){
    callback(err);
});

//等价于
ep.bind('error', function(err){
    //卸载掉所有handler
    ep.unbind();
    //异常回调
    callback(err);
});

fail方法监听了error事件,默认处理卸掉所有handler,并调用回调函数。

throw方法

throwep.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 一枝猪

转载于:https://www.cnblogs.com/chunzhulovefeiyue/p/7234153.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值