zoukankan      html  css  js  c++  java
  • 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 一枝猪

  • 相关阅读:
    RDMA技术详解(二):RDMA Send Receive操作
    RDMA技术详解(一):RDMA概述
    Fedora中制作UEFI/BIOS启动的U盘安装盘
    Fedora中制作BIOS启动的U盘安装盘
    chkdsk /f
    单片机原理及应用---实验计划
    LeetCode 645. Set Mismatch(错误的集合)
    LeetCode 401. Binary Watch(二进制手表)
    LeetCode 852. Peak Index in a Mountain Array(山脉数组的峰顶索引)
    LeetCode 518. Coin Change 2(零钱兑换 II)
  • 原文地址:https://www.cnblogs.com/chunzhulovefeiyue/p/7234153.html
Copyright © 2011-2022 走看看