使用AJAX更新来限制淘汰率

时间:2018-07-15 17:01:51

标签: javascript ajax events knockout.js rate-limiting

我正在尝试创建一个HTML表单,该表单根据下拉菜单中选择的内容更新其某些值。视图模型如下所示:

function RoomViewModel() {
    var self = this;

    self.companyOptions = @Html.Raw({ ... });
    self.companyValue = ko.observable().extend({ rateLimit: 5000 });
    self.companyInfo = ko.observable();
    ko.computed(function() {
        if (self.companyValue()) {
            $.getJSON('@Html.GenerateActionLinkUrl("GetCompanyAndPlans")', {}, self.companyInfo);
        }
    });
}

ko.options.deferUpdates = true;
ko.applyBindings(new RoomViewModel());

然后我将select下拉列表绑定到companyValue,如果我多次更改选择,则computed只会在5秒钟后开始显示当前选定的内容。值。这几乎可以完成我想要的事情,但是一个问题是,第一次更改下拉列表时,您不必等待5秒钟-它应该立即进行JSON调用。速率限制是在第一个更改到5秒后的 之间停止进一步的JSON请求。那么如何使它立即执行JSON请求并更新 first 更改?

2 个答案:

答案 0 :(得分:0)

var ratelim = 0; // global rate limit 

function RoomViewModel() {
    var self = this;

    self.companyOptions = @Html.Raw({ ... });

    if(ratelim == 0){
      self.companyValue = ko.observable().extend({ rateLimit: ratelim }); // trigger the change without a delay 
      ratelim = 5000; // update the ratelim so the next request has a 5 second delay 
    } else { // ratelimit is not 0 (not first request), go ahead with regular rate-limited change: 
      self.companyValue = ko.observable().extend({ rateLimit: ratelim }); // extend the observable, with current ratelim
    }

    self.companyInfo = ko.observable();
    ko.computed(function() {
        if (self.companyValue()) {
            $.getJSON('@Html.GenerateActionLinkUrl("GetCompanyAndPlans")', {}, self.companyInfo);
        }
    });
}

ko.options.deferUpdates = true;
ko.applyBindings(new RoomViewModel());

我相信这应该可以解决问题。我使用了一个全局变量(ratelim)来允许您的函数检测它是否是第一个请求...确实,您应该将true或false的变量值更改为是否正在进行请求,以便有0速率限制(如果用户已经闲置了一段时间)。再说一遍,如果第二个请求发生在第一个请求之后的20秒,则无需再有5秒的延迟。

答案 1 :(得分:0)

有趣的问题。我开始使用它,得出的结论是您需要为此定制一个扩展器。 I found one模拟了rateLimit并进行了一些更改,似乎确实可以满足您的需求。

您应该可以这样做:

self.companyValue = ko.observable().extend({ customRateLimit: 5000 });

并立即进行初始更改,并限制其后的速率。

Here is the fiddle

以下是可运行的代码段:

ko.extenders.customRateLimit = function(target, timeout) {
  var writeTimeoutInstance = null;
  var currentValue = target();
  var updateValueAgain = false;
  var interceptor;
  var isFirstTime = true

  if (ko.isComputed(target) && !ko.isWriteableObservable(target)) {
    interceptor = ko.observable().extend({
      customRateLimit: timeout
    });
    target.subscribe(interceptor);
    return interceptor;
  }

  return ko.dependentObservable({
    read: target,
    write: function(value) {
      var updateValue = function(value) {
        if (isFirstTime) {
          target(value);
          isFirstTime = false;
        } else {
          if (!writeTimeoutInstance) {
            writeTimeoutInstance = setTimeout(function() {
              writeTimeoutInstance = null;
              if (updateValueAgain) {
                updateValueAgain = false;
                updateValue(currentValue);
              }
              target(value);
            }, timeout);
          }
        }
      }
      currentValue = value;
      if (!writeTimeoutInstance)
        updateValue(currentValue);
      else
        updateValueAgain = true;
    }
  });
}

function AppViewModel() {
  this.text = ko.observable().extend({
    customRateLimit: 1000
  });
  this.rateLimited = ko.computed(this.text).extend({
    customRateLimit: 1000
  });
}

ko.applyBindings(new AppViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-debug.js"></script>

<h4>Change value is default so move the focus out of the input to change values.</h4>

<div>
  Enter Text: <input type='text' data-bind='value: text' />
</div>
<div>
  Rete Limited <small>(after the first change)</small>: <input type='text' data-bind='value: text' />
</div>
<div>
  Rete Limited Computed <small>(after the first change)</small>: <input type='text' data-bind='value: rateLimited' />
</div>

在第一个文本框中输入文本后,请注意在其他文本框中如何立即进行更改。但是,第一个更改之后的任何更改都会被延迟

借助此方法,您可以扩展可观察值和计算可观察值。