Node.js之eventproxy详解

安装git

npm install eventproxy --savegithub

调用sql

var EventProxy = require('eventproxy');数据库

异步协做

多类型异步协做

此处以页面渲染为场景,渲染页面须要模版、数据。假设都须要异步读取。npm

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

相关文章
相关标签/搜索