2015-03-31 92 views
2

我目前正试图提高自己的重构技巧,我有一段代码,我写了两个非常相似的方法,并且我试图围绕简化我的头部臃肿的代码,任何建议将受到欢迎。试图了解JavaScript中的DRY原理

正如你所看到的,这两种方法非常相似,唯一真正的区别是POST的URL。

authenticateA : function(e) { 
    var $this = $(e.target).closest('[data-fn]') 
    , text = $this.text() 
    , that = this; 

    $this.text('Authenticating...').addClass("auth-button-disable") 

    $.ajax({ 
    type : 'POST', 
    url : '/A_authentications/update/', 
    data : { _method : 'PUT', sms_token : this.$el.find('#sms-input').val() }, 
    complete: function(xhr) { 

     if (xhr.status === 200) 
     that.relocate(); 
     else { 
     $this.text(text).removeClass("auth-button-disable"); 
     that.handleError(xhr.status); 
     } 
    }, 
    dataType : 'json' 
    }); 
}, 

authenticateB : function(e) { 
    var $this = $(e.target).closest('[data-fn]') 
    , text = $this.text() 
    , that = this; 

    $this.text('Authenticating...').addClass("auth-button-disable") 

    $.ajax({ 
    type : 'POST', 
    url : '/B_authentications/', 
    data : { otp : this.$el.find('#B-input').val() }, 
    complete: function(xhr) { 
     if (xhr.status === 200) 
     that.relocate(); 
     else { 
     $this.text(text).removeClass("auth-button-disable"); 
     that.handleError(xhr.status) 
     } 
    }, 
    dataType : 'json' 
    }); 
} 

我称之为一个事件的方法是单击功能块:

'click [data-fn="authenticate-A"]' : 'authenticateA', 
'click [data-fn="authenticate-B"]' : 'authenticateB' 

我想这可能是重构为一个方法或两个苗条的方法,我只是不知道从哪里开始,再次感谢提前。

+2

的到重构两种方法成一个关键是确定什么是两个并可能这些差异在任何一个功能参数或从DOM元素中指定之间的差异。作为一个起点,看起来url和类型是不同的,这些值可以来自

标签本身,然后你可以使用jquery进行检索。 – hofan41 2015-03-31 17:01:49

+1

与'200'一起使用ajax'complete'方法是多余的。只需使用'done'方法。 'complete'方法也被弃用。 – vsync 2015-03-31 17:09:15

+1

使用'complete'参数[未弃用](http://stackoverflow.com/a/15821199/2788131)。 '.ajax({})。complete()',方法是。 – D4V1D 2015-03-31 17:13:19

回答

3

你可以有一个生成的函数功能:

var authDetailsA = { 
    url : '/A_authentications/update/', 
    dataFunc : function (this) { 
    return { _method : 'PUT', sms_token : this.$el.find('#sms-input').val() }; 
    } 
}; 
var authDetailsB = { 
    url : '/B_authentications/', 
    dataFunc : function (this) { 
    return { otp : this.$el.find('#B-input').val() }; 
}; 
authenticateA : generateAuthFunction(authDetailsA); 
authenticateB : generateAuthFunction(authDetailsB); 

你可以称之为:

generateAuthFunction : function(authDetails) { 
    return function (e) { 
    var $this = $(e.target).closest('[data-fn]') 
    , text = $this.text() 
    , that = this; 

    $this.text('Authenticating...').addClass("auth-button-disable") 

    $.ajax({ 
     type : 'POST', 
     url : authDetails.url, 
     data : authDetails.dataFunc(this), 
     complete: function(xhr) { 

     if (xhr.status === 200) 
      that.relocate(); 
     else { 
      $this.text(text).removeClass("auth-button-disable"); 
      that.handleError(xhr.status); 
     } 
     }, 
     dataType : 'json' 
    }); 
    }; 
} 

然后你生成它它像以前一样:

'click [data-fn="authenticate-A"]' : 'authenticateA', 
'click [data-fn="authenticate-B"]' : 'authenticateB' 

我认为这可能会引入不必要的复杂性,但它更干。

+0

即使在骨干视图?你在哪里调用发电机功能? – 2015-03-31 20:02:44

+1

您可以在之前定义authenticateA和authenticateB函数的地方调用它。如果用前两个代码块替换功能的定义,它将具有相同的效果,authenticateA和authenticateB将像之前一样定义。 – jstriebel 2015-04-01 01:58:54

+0

啊,我明白了。我想我挂在哪里是var authDetails块的位置与所有其他代码所在的返回Backbone.View.extend块的关系。 – 2015-04-03 20:34:26

1

尝试(未测试的代码):

authenticate: function(t, e) { // t = 'A' || 'B' 
    var $this = $(e.target).closest('[data-fn]') 
    , text = $this.text() 
    , that = this 
    , url 
    , data; 

    $this.text('Authenticating...').addClass("auth-button-disable") 

    // conditionnaly set up your variables 
    if(t == 'A') { 
     data = { _method : 'PUT', sms_token : this.$el.find('#sms-input').val() }; 
     url = '/A_authentications/update/'; 
    } else if(t == 'B') { 
     url = '/B_authentications/'; 
     data = { otp : this.$el.find('#B-input').val() }; 
    } 

    $.ajax({ 
    type : 'POST', 
    url : url, // use them 
    data : data, // use them 
    complete: function(xhr) { 

     if (xhr.status === 200) 
     that.relocate(); 
     else { 
     $this.text(text).removeClass("auth-button-disable"); 
     that.handleError(xhr.status); 
     } 
    }, 
    dataType : 'json' 
    }); 
}, 
+0

你会怎样称呼点击事件? – 2015-03-31 19:55:56

1

您可以只检查authenticate函数中的data-fn属性。

authenticate: function (e) {   
     var $this = $(e.target).closest('[data-fn]'), 
      text = $this.text(), 
      that = this; 
     $this.text('Authenticating...').addClass("auth-button-disable"); 
     var fn = $this.data("fn"); 

     switch (fn) { 
      case "authenticate-A": 
       data = { 
        _method: 'PUT', 
        sms_token: this.$el.find('#sms-input').val() 
       }; 
       url = '/A_authentications/update/'; 
       break; 
      case "authenticate-B": 
       data = { 
        otp: this.$el.find('#B-input').val() 
       }; 
       url = '/B_authentications/update/'; 
       break; 

     } 

     $.ajax({ 
      type: 'POST', 
      url: url, 
      data: data, 
      complete: function (xhr) { 

       if (xhr.status === 200) that.relocate(); 
       else { 
        $this.text(text).removeClass("auth-button-disable"); 
        that.handleError(xhr.status); 
       } 
      }, 
      dataType: 'json' 
     }); 


    } 
2
  1. 抽象掉您的要求。将您的应用逻辑混合到您的视图中只能混淆图片。让我们创建一个Authentication模块:

    var Authentication = (function(Backbone, _) { 
        function whoGoesThere(opts) { 
         opts = _.extend({}, opts, { 
          type : 'POST', 
          dataType: 'json' 
         }); 
    
         return Backbone.$.ajax(opts); 
        } 
    
        return { 
         A: function(data) { 
          data = _.extend({}, data, { 
           _method : 'PUT' 
          }); 
          return whoGoesThere({ 
           url : '/A_authentications/update/', 
           data: data    
          }); 
         }, 
         B: function(data) { 
          return whoGoesThere({ 
           url : '/B_authentications/', 
           data: data    
          }); 
         } 
        }; 
    })(Backbone, _); 
    
  2. 配置你的意见来处理与功能,而不是一个函数名的事件,传递自己的价值观,以适当的方法与前一个模块,然后委托返回的承诺,共同处理:

    events: { 
        'click [data-fn="authenticate-A"]': function(e) { 
         var promise = Authentication.A({ 
          sms_token : this.$el.find('#sms-input').val() 
         }); 
         this.onAuthentication(e, promise); 
        }, 
        'click [data-fn="authenticate-B"]': function(e) { 
         var promise = Authentication.B({ 
          otp : this.$el.find('#B-input').val() 
         }); 
         this.onAuthentication(e, promise); 
        } 
    } 
    
  3. 处理的承诺(这里的Ajax对象,但可能是任何东西)

    onAuthentication: function(e, promise) { 
        var $this = $(e.target).closest('[data-fn]') 
        , text = $this.text() 
        , that = this; 
    
        $this.text('Authenticating...').addClass("auth-button-disable"); 
    
        promise.done(function() { 
         that.relocate(); 
        }); 
        promise.fail(function(xhr) { 
         that.handleError(xhr.status); 
        }); 
        promise.always(function() { 
         $this.text(text).removeClass("auth-button-disable");   
        }); 
    } 
    

并且一个演示http://jsfiddle.net/s3ydy3u6/1/