Think Tech About Rss

老掉牙技术重拾 Watcher Sender 【状态机编程】

2015-12-26 Tech

写在前面

最近在研究状态编程的思想,不想歪打正着碰到了js实现dataMap,然后引申发现这个玩意可以做到类vue bus的效果,这里记录一下发布出来,希望对一些研究全局状态监控和数据双向绑定的同学有所帮助吧,下面具体在研究数据双向绑定的原理。

首先实现一个dataMap

分析一下,dataMap都需要什么功能,(之前有一篇文章咱们是说过es6新增对象map和set,mao和这个有点像,但map是一个二位数据 链接>>)下面列举一下:

  • 增、删、改、查,这个删要可以指定key去删除。
  • 既然自己搞那就搞点原生不具备的东西,方便使用提高性能。mapData具备判断是否为空、遍历(类原生高阶函数map方法)、获取键值数组、更加方便的获取mapData长度。
    来看一下dataMap的结构图:

来实现一下:

//先给原生数组加一个remove()方法
Array.prototype.remove = function(s) {
    for (var i = 0; i < this.length; i++) {
        if (s == this[i])
            this.splice(i, 1);
    }
}

具体实现以下dataMap这个构造函数

var DataMap = function(){
    /** 存放key */
    this.keys = new Array();
    /** 存放数据 */
    this.data = new Object();
    /**
     * 插入数据
     * @param {String} key
     * @param {Object} value
     */
    this.put = function(key, value) {
        if(this.data[key] == null){
            this.keys.push(key);
        }
        this.data[key] = value;
    };
    /**
     * 获取某键对应的值
     * @param {String} key
     * @return {Object} value
     */
    this.get = function(key) {
        return this.data[key];
    };
    /**
     * 删除一个键值对
     * @param {String} key
     */
    this.remove = function(key) {
        this.keys.remove(key);
        this.data[key] = null;
    };
    /**
     * 遍历Map,执行处理函数
     *
     * @param {Function} 回调函数 function(key,value,index){..}
     */
    this.each = function(fn){
        if(typeof fn != 'function'){
            return;
        }
        var len = this.keys.length;
        for(var i=0;i<len;i++){
            var k = this.keys[i];
            fn(k,this.data[k],i);
        }
    };
    /**
     * 获取键值数组(类似Java的entrySet())
     * @return 键值对象{key,value}的数组
     */
    this.entrys = function() {
        var len = this.keys.length;
        var entrys = new Array(len);
        for (var i = 0; i < len; i++) {
            entrys[i] = {
                key : this.keys[i],
                value : this.data[i]
            };
        }
        return entrys;
    };
    /**
     * 判断Map是否为空
     */
    this.isEmpty = function() {
        return this.keys.length == 0;
    };
    /**
     * 获取键值对数量
     */
    this.size = function(){
        return this.keys.length;
    };
};

这个mapData完事,下来在说说用这个来做watcher和sender,同样的来看张流程图分析一下原理:

上代码:

var eventController = (function() {
    var instantiated;  //实例化标识符

    function init() {
        /*这里定义单例代码*/
        var eventContainer = new DataMap();

        return {
            registerEvent: function(event, operator) {
                if (typeof operator != "function") {
                    return;
                }

                var listenerList = eventContainer.get(event);
                if (listenerList == null) {
                    listenerList = new Array();
                    eventContainer.put(event, listenerList);
                }

                listenerList.push(operator);
            },

            wireEvent: function(event, param) {
                var listenerList = eventContainer.get(event);
                if (listenerList == null) {
                    return;
                }

                for (var i = 0; i < listenerList.length; i++) {
                    listenerList[i](param);
                }
            },

            publicProperty: 'test'
        };
    }

    return {
        //避免重新生成DataMap实例
        getInstance: function() {
            if (!instantiated) {
                instantiated = init();
            }
            return instantiated;
        }
    };
})();

var sender = function(event, param) {
    eventController.getInstance().wireEvent(event, param);
}

var watcher = function(event, operator) {
    eventController.getInstance().registerEvent(event, operator);
}

如果你很熟悉vuebus的使用那么这个也很好理解,请看使用方法:

function event(e){
    alert(e)
}
watcher('everyString',event)
//在其他页面执行sender的时候event会执行

sender('everyString','111')  //alert(111)

完事,有没有get到新技能。

Pre Next