试图理解Javascript中的干式原理

试图理解Javascript中的干式原理,javascript,jquery,performance,backbone.js,dry,Javascript,Jquery,Performance,Backbone.js,Dry,我目前正在努力提高我的重构技能,我有一段代码,我写的代码有两种非常相似的方法,我正在努力简化我臃肿的代码,欢迎任何建议 正如您所看到的,这两种方法非常相似,唯一真正的区别是文章的URL authenticateA : function( e ) { var $this = $( e.target ).closest( '[data-fn]' ) , text = $this.text() , that = this; $this.text( 'Authenticatin

我目前正在努力提高我的重构技能,我有一段代码,我写的代码有两种非常相似的方法,我正在努力简化我臃肿的代码,欢迎任何建议

正如您所看到的,这两种方法非常相似,唯一真正的区别是文章的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'
我认为这些可以重构成一个或两个更精简的方法,我只是不确定从哪里开始,再次提前感谢。

Try(未经测试的代码):


您可以使用生成这些函数的函数:

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'
    });
  };
}
然后使用以下方法生成:

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);
你可以像以前那样称呼它:

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

我认为这甚至可能会引入不必要的复杂性,但它更加枯燥。

您只需检查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'
        });


    }
  • 把你的要求抽象掉。将应用程序逻辑与视图混为一谈只会让情况变得混乱。让我们创建一个
    身份验证
    模块:

    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, _);
    
  • 将视图配置为使用函数而不是函数名来处理事件,将值传递给上一个模块上的相应方法,然后将返回的承诺委托给公共处理程序:

    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);
        }
    }
    
  • 处理承诺(这里是Ajax对象,但它可以是任何东西)


  • 一个演示

    将两个方法重构为一个的关键是确定这两个方法之间的区别,这些区别可以在函数参数中指定,也可以从dom元素中指定。作为起点,url和类型似乎不同,这些值可以来自标记本身,然后可以使用jquery检索。使用ajax
    complete
    方法和
    200
    是多余的。只需使用
    done
    方法即可。另外,不推荐使用
    complete
    方法。使用
    complete
    参数<代码>$.ajax({}).complete()
    ,方法是。这个问题太广泛了。正如你所看到的,有各种各样的方法。我认为这更适合于如何调用单击事件?即使是在主干视图中?在哪里调用生成器函数?可以在之前定义AuthenticateTea和authenticateB函数的地方调用它。如果用前两个代码块替换函数的定义,它将具有相同的效果,authenticateA和authenticateB将像以前一样定义。啊,我明白了。我想挂断的地方是将var authDetails块放在与所有其他代码所在的return Backbone.View.extend块相关的位置。
    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);
        }
    }
    
    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");        
        });
    }