使用trigger解耦

    在公司里面实习了一周,前四天都在看代码,终于在第四天快结束的时候接到了一个任务:完成一个打点上报功能,方便统计分析客户的行为。

由于需要设置一些必要的头信息,在项目中已经把JQuery的ajax方法包装成 base.ajax(options) ,调用方法和 $.ajax(options) 一样。看了一下源码,果然,使用的是装饰者。

     base是整个项目的基础模块 ,这里提一下。(这里先埋下伏笔)

    这里使用装饰者是一种很合适的办法,装饰者本来就是为了在不影响原来的前提下增加额外的东西,返回的装饰者必须完全兼容以前的东西(我实在不知道该怎么表达这个= =,具体可以百度或者去翻设计模式。)。

    看到这里一下子就有种接近真相的感觉:打点上报不也是属于附加的功能吗?用装饰者不是正好?于是便有了第一个方案:

//base.js
base.ajax = function(options) {
...
//这里不贴详细代码了,主要的是下面这句:
report(options);
...
}
//report.js
//一些url的白名单映射什么的...

      fns = $.isArray(fns) ? fns : [fns];

       //根据whiteList检测是否需要打点
       var url = param.url;
       //不需要上报,直接原路返回
       if(whiteList[url] === void 0)
           return;

       var platform = Life.report.platform;
       var p = platform.isPC? 'PC' :
           platform.isWx ? 'WX' :
               platform.isApp ? 'APP' : 'PC';//取得platform,默认是PC

       var commonpart = commonPart(url);//公共部分

       $.each(fns, function(v,i) {
           //如果是函数,进行装饰
           if(typeof v === 'function'){
               var originalCb = v;
               param[i] = function(){
                   var args = arguments;//原本的请求返回的结果
                   var reportData = $.extend(commonpart, actions[p][whiteList[url]](param, args));//需要上报的数据

                   var params = {
                       url : Life.report.remoteUrl,
                       data : reportData,
                       context : param.context,//保证跟换了回调后上下文不变
                       success : function(result) {
                           //result.ret
                           console.log('上报成功');
                           originalCb.apply(this, args);
                       },
                       //出现了错误后由于恢复现场下面的error不回被替换
                       //error : function(xhr, status, error) {
                       //    console.error('上传失败.' + status + ':' + error.toString());
                       //    originalCb.apply(this, args);
                       //}
                       //other common params
                   };
                   $.ajax(params);//上报请求
               };
           }
       });

基本的思路也是替换掉原本的success和error回调,并把原本的success和error包装进上报接口的回调方法中。

    使用了装饰者,跑起来应该也没什么问题。然后问了一下Givon的意见,看一下这个方案的可行性。

Givon:要是report.js里面执行的代码出错了岂不是原本的回调不能正常执行?上报只是一个次要功能,不能影响原本重要的功能。

    恍然大悟,想了一下,有了改进版本:

function securityFn(){
//把原先的代码移入这里
//这里使用函数包装是为了给try/catch创建一个相对干净的上下文环境,避免try/catch拷贝词法环境带来性能损失。(try/catch的性能问题可以百度一下~)

}

var originalOptions = $.extend({}, options};//保存现场
try{
  securityFn();
}
catch(e){
  //发生错误,恢复现场
  $.extend(options, originalOptions);
}

总的来说,就是把上报的代码放在try/catch中,如果代码出错后会直接恢复原本的回调,不影响原本逻辑的执行。(后来想了一下xhr出错的问题应该屏蔽掉)

现在看起来应该没什么问题了,然后又和Givon讨论了一下:

Givon:base是整个项目的基本模块,不应该去依赖report这个次要模块。

再一次恍然大悟。后台Givon提供了一个解决方案,就是文章标题的主角: trigger

trigger 是JQuery提供的触发事件的方法,原生JS的话可以使用 dispatchEvent() 来代替。

使用trigger可以很方便地实现模块之间的解耦:

在需要上报的地方直接触发report事件(trigger('report', data)),然后在report模块中监听report事件。

这样做的好处除了代码实现简单、逻辑清晰外,还能解决了base和report模块之间的耦合问题:就算report模块没有加载或者出错,base模块只不过是触发了一次report事件,对原本的业务逻辑没有任何影响。

其实使用 trigger 实际上是使用了代理这种方案。想起设计模式中的代理模式,就是为了解决模块之间耦合,使其单独变化的。(当初看的时候没怎么理解代理模式的实际应用场景,现在看来这是一个非常合适的例子)

最后说一下上报方式:
原本的设计中是使用ajax上报,实现起来比较麻烦,后来卡哥提示一下这种(不太重要的)上报一半都是直接把参数塞进 img 便签的src属性后直接插入body,使用get的方式直接上报。

Summary


在这次的小任务中感觉收获良多,自己一开始没有分析好主要矛盾和次要矛盾走了许多弯路,下次要注意。除了巩固了设计模式,也学习了很多有用的技巧。自一次感觉开发经验很重要,Givon和卡哥都是很好的仙贝,这次的任务还没完成,有学到新东西再来分享一下。:)

感觉自己写的东西不太像技术分享反而像流水账日记,辛苦大家了= =。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值