【问题标题】:Knockout rate limiting with AJAX updates使用 AJAX 更新限制淘汰率
【发布时间】:2018-12-23 07:49:11
【问题描述】:

我正在尝试创建一个 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,如果我多次更改选择,只有在5 秒后computed 才会启动并显示当前选择的值。这接近于做我想做的事,但一个问题是第一次更改下拉列表时,您不必等待 5 秒 - 它应该立即进行 JSON 调用。速率限制是在第一次更改和 5 秒后之间停止进一步的 JSON 请求。那么如何让它立即执行 JSON 请求并更新 first 更改?

【问题讨论】:

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


【解决方案1】:
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 秒。

【讨论】:

  • 嗯???这将如何运作?它只会在构建新的 RoomViewModel 期间运行一次。
  • 好吧,如果你只运行一次,那么你只需要在第一次之后更新速率限制。 {rateLimit: 0} 应该是默认值,然后您需要在完成一次后将其更新为 5000。
【解决方案2】:

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

有了这个你应该可以做到:

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

并且让初始更改是即时的,并且任何后续更改都是速率限制的。

Here is the fiddle

这里是可运行的代码sn-p:

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>

在第一个文本框中输入文本后,请注意其他文本框中的更改是如何立即发生的。然而,第一次之后的任何更改都会延迟

有了这个,你可以扩展 observables 和计算 observables。

【讨论】:

    猜你喜欢
    • 2021-03-08
    • 1970-01-01
    • 2012-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-21
    相关资源
    最近更新 更多