Ограничение скорости нокаута с помощью обновлений AJAX
Я пытаюсь создать форму 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. Ограничением скорости является остановка дальнейших запросов JSON между первым изменением и 5 секундами позже. Итак, как я могу сделать это немедленно сделать запрос JSON и обновить для первого изменения?
2 ответа
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-секундную задержку.
Интересная проблема. Я начал играть с ним, и пришел к выводу, что для этого вам нужен специальный расширитель. Я нашел тот, который имитирует rateLimit и с некоторыми изменениями, кажется, отвечает вашим потребностям.
С этим вы должны быть в состоянии сделать:
self.companyValue = ko.observable().extend({ customRateLimit: 5000 });
И имейте начальное изменение быть мгновенным, и любой последующий быть ограниченным скоростью.
Вот фрагмент кода для запуска:
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>
Обратите внимание, после ввода текста в первом текстовом поле, как изменения немедленно в других. Однако любое изменение после первого откладывается
При этом вы можете расширить наблюдаемые и вычисляемые наблюдаемые.