一不小心翻车了-(angularjs 1.6X) 由Eventbus使用异常说起

Posted 阿拉蕾家的小铁匠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一不小心翻车了-(angularjs 1.6X) 由Eventbus使用异常说起相关的知识,希望对你有一定的参考价值。

一  在angular框架使用过程中,我们经常碰到控制器之间进行通信的问题,

方法有多种,今天记录的是通过factory通信,先上代码:

//控制器之间共享
angular.module(‘app‘).factory("EventBus", function() {
   
    var eventMap = {};    
    var EventBus = {
     
  on : function(eventType, handler) {
            
       if (!eventMap[eventType]) 
    {
           eventMap[eventType] = [];
       }
     eventMap[eventType].push(handler);
   },

   off : function(eventType, handler) {
       for (var i = 0; i < eventMap[eventType].length; i++) 
    {
            if (eventMap[eventType][i] === handler) {              
                eventMap[eventType].splice(i, 1);
                 break;
            }
        }   
   },
     fire :
function(event) { var eventType = event.type; if (eventMap && eventMap[eventType]) { for (var i = 0; i < eventMap[eventType].length; i++) { eventMap[eventType][i](event); } }   } }; return EventBus; });

调用发布事件时候

angular.module(‘app‘).controller(‘testcontroller‘,function($scope,$state,EventBus) {
    //发布事件
    EventBus.fire({
        type:‘testevent‘,
        data:{
            List:1
        }
    })    
});

调用监事件听时候

angular.module(‘app‘).controller(‘testcontroller‘,function($scope,$state,EventBus) {     
        
    EventBus.on("testevent",function(event){
        var data=event.data;        
        console.log(data);
    });
});

这个方法可以在多个地方监听同一个事件,代码又简练,在项目中用的很舒服

二 但是用起来之后问题来了,主要有2个BUG

  第一个就是off取消事件

  off : function(eventType, handler) {
       for (var i = 0; i < eventMap[eventType].length; i++) 
    {
           //这个判断对比的是2个函数,永远都是false
            if (eventMap[eventType][i] === handler) {              
                eventMap[eventType].splice(i, 1);
                 break;
            }
        }   
   },    

 取消时判断对比的是2个函数,永远都是false。 这个问题简单的解决方法就是把2个函数转化成string 再对比

 代码如下

off : function(eventType, handler) {
            
            for (var i = 0; i < eventMap[eventType].length; i++) {

                if (eventMap[eventType][i].toString() === handler.toString()) {
                    eventMap[eventType].splice(i, 1);
                    break;
                }
            }
        },

更完善的函数比较可以引用函数对比函数

/**
     * 返回指定变量的数据类型
     * @param  {Any} data
     * @return {String}
     */
    function type (data) {
        return Object.prototype.toString.call(data).slice(8, -1);
    }
        
    
    /**
     * 对比两个function是否一样
     * 主要对比两者toString是否一样,
     * 对比会去掉函数名进行对比,其它哪怕差个回车都会返回false
     * 
     * @param  {[type]} fn1
     * @param  {[type]} fn2
     * @return {[type]}
     */
    function equalFunction (fn1, fn2) {
        var type1 = type(fn1),
            type2 = type(fn2);
            
        console.log(type1,type2)
        if (type1 !== type2 || type1 !== ‘Function‘) {
            return false;
        };
        if (fn1 === fn2) {
            return true;
        };
        var reg = /^function[\s]*?([\w]*?)\([^\)]*?\){/;
        var str1 = fn1.toString().replace(reg,function ($,$1) {
            return $.replace($1,"");
        });
        var str2 = fn2.toString().replace(reg,function ($,$1) {
            return $.replace($1,"");
        });
        console.log(str1,str2);
        if (str1 !== str2) {
            return false;
        };
        return true;
    }


        off : function(eventType, handler) {
            
            for (var i = 0; i < eventMap[eventType].length; i++) {
                //if (eventMap[eventType][i] === handler) {
                if (equalFunction(eventMap[eventType][i],handler)) {
                //if (eventMap[eventType][i].toString() === handler.toString()) {
                    eventMap[eventType].splice(i, 1);
                    break;
                }
            }
        },

这个解决方案相对比较完善一些

 

三  第二个Bug就比较致命了

一开始我发现on监听执行过程中 获取的$scope 变量的值不是最新的!!! 差点让我怀疑人生。

仔细研究之后发现同一个on监听执行了好多次(呵呵哒)

原因在于 通信监听的on事件 注册了多次!!!

注册多次是由于on所在的controller对应的页面     通过$state.go可跳转至其它页面  也可以跳转回来

跳转回来多次 同一个on监听就被注册了多次 ,而且每次的on监听封装的$scope变量都是当次跳转到其它页面之前的值

最后fire事件发布时,on就会有多个监听依次之下(同一个on监听事件 执行多次 但是每次的$scope变量可能不一样)

so........我们在注册on事件时候需要查看下是否已经注册过该事件了 。。。。然后删除旧的 注册最新的(封装了最新的$scope变量)

代码

        on : function(eventType, handler) {
            
            if (!eventMap[eventType]) {
                eventMap[eventType] = [];
            }
            //注册on事件时候需要查看下是否已经注册过该事件了 。。。。然后删除旧的 注册最新的(封装了最新的$scope变量)
            this.off(eventType, handler);
            
            eventMap[eventType].push(handler);
        
        },

四 修复Bug之后  开车的代码如下  又可以愉快的发车咯

//控制器之间共享
angular.module(‘yun.homework‘).factory("EventBus", function() {
   
    var eventMap = {};

    /**
     * 返回指定变量的数据类型
     * @param  {Any} data
     * @return {String}
     */
    function type (data) {
        return Object.prototype.toString.call(data).slice(8, -1);
    }
        
    
    /**
     * 对比两个function是否一样
     * 主要对比两者toString是否一样,
     * 对比会去掉函数名进行对比,其它哪怕差个回车都会返回false
     * 
     * @param  {[type]} fn1
     * @param  {[type]} fn2
     * @return {[type]}
     */
    function equalFunction (fn1, fn2) {
        var type1 = type(fn1),
            type2 = type(fn2);
            
        console.log(type1,type2)
        if (type1 !== type2 || type1 !== ‘Function‘) {
            return false;
        };
        if (fn1 === fn2) {
            return true;
        };
        var reg = /^function[\s]*?([\w]*?)\([^\)]*?\){/;
        var str1 = fn1.toString().replace(reg,function ($,$1) {
            return $.replace($1,"");
        });
        var str2 = fn2.toString().replace(reg,function ($,$1) {
            return $.replace($1,"");
        });
        console.log(str1,str2);
        if (str1 !== str2) {
            return false;
        };
        return true;
    }
    
    var EventBus = {
        on : function(eventType, handler) {
            
            if (!eventMap[eventType]) {
                eventMap[eventType] = [];
            }
            this.off(eventType, handler);

            eventMap[eventType].push(handler);

        },

        off : function(eventType, handler) {
            
            for (var i = 0; i < eventMap[eventType].length; i++) {
                //if (eventMap[eventType][i] === handler) {
                //if (equalFunction(eventMap[eventType][i],handler)) {
                if (eventMap[eventType][i].toString() === handler.toString()) {
                    eventMap[eventType].splice(i, 1);
                    break;
                }
            }
        },

        fire : function(event) {
        
            var eventType = event.type;
            if (eventMap && eventMap[eventType]) {
        
                for (var i = 0; i < eventMap[eventType].length; i++) {
                    eventMap[eventType][i](event);
                }
            }
        }
    };
    return EventBus;
});

 


以上是关于一不小心翻车了-(angularjs 1.6X) 由Eventbus使用异常说起的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS 1.6 升级代码以登录不再使用 REST?

AngularJS 1.6 + ES6 - $doCheck 被调用两次

将 AngularJs 1.5 升级到 1.6 - $compile reg 控制器实例的更改会影响哪些确切的绑定?

AngularJS 1.6 + ES6 - 将jquery ui-grid回调数据返回到控制器[重复]

通过数组的AngularJS 1.6返回对象数据

物流货车运输途中翻车?资产监控设备减少事件损失