我显示或隐藏"正在加载"通过将其可见性绑定到名为waiting
的可观察对象,我的UI上的指示符,其定义如下:
// Viewmodel
var outstandingRequests = ko.observable(0);
// true if any requests are outstanding
var waiting = ko.computed(function() {
return outstandingRequests() > 0;
}.extend({ throttle: 500 });
// These are called when AJAX requests begin or end
function ajaxBegin() {
outstandingRequests(++outstandingRequests());
}
function ajaxEnd() {
outstandingRequests(--outstandingRequests());
}
<!-- View -->
<div data-bind="visible: waiting">Please wait, loading...</div>
我限制了waiting
观察点,因为我不希望加载消息出现,除非请求花费很长时间(在这种情况下大于500毫秒),以增加感知申请的速度。问题是,一旦长时间运行的请求完成,加载指示器就不会消失,直到另外500ms过去。相反,当最后一个未完成的请求完成时,我希望waiting
立即翻转为 。
我首次尝试使用valueHasMutated()
进行修复,但更新仍然延迟。
function ajaxEnd() {
outstandingRequests(--outstandingRequests());
// If that was the last request, we want the loading widget to disappear NOW.
outstandingRequests.valueHasMutated(); // Nope, 'waiting' still 500ms to update :(
}
如何绕过油门延长并强制waiting
立即更新?
答案 0 :(得分:4)
当你扩展一个observable时,扩展器通常会将observable与另一个具有所需行为的observable包装起来。您可以保留对原始observable的引用,这将允许您直接写入它,同时正常暴露您的可观察的受限制版本。
如,
var myObservable = ko.observable('foo');
var myThrottledObservable = myObservable.extend({ throttle: 500 });
myThrottledObservable('bar'); // delayed
myObservable('baz'); // immediate
在您的特定用例中,不是限制waiting
observable,而是限制outstandingRequests
observable并使用waiting
中的限制值。
var outstandingRequests = ko.observable(0);
// throttled requests for the waiting observable
var throttledOutstandingRequests = outstandingRequests.extend({ throttle: 500 });
// true if any requests are outstanding
var waiting = ko.computed(function() {
return throttledOutstandingRequests() > 0;
};
// These are called when AJAX requests begin or end
function ajaxBegin() {
outstandingRequests(++outstandingRequests());
}
function ajaxEnd() {
outstandingRequests(--outstandingRequests());
}
立即写入您的outstandingRequests
观察点,但您的waiting
观察点将被有效限制。
或者,我认为更清洁的解决方案是重新实现throttled
扩展程序以添加立即更新的功能。
ko.extenders['throttleEx'] = function(target, timeout) {
// Throttling means two things:
// (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
// notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
target['throttleEvaluation'] = timeout;
// (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
// so the target cannot change value synchronously or faster than a certain rate
var writeTimeoutInstance = null;
var throttled = ko.dependentObservable({
'read': target,
'write': function(value) {
clearTimeout(writeTimeoutInstance);
writeTimeoutInstance = setTimeout(function() {
target(value);
}, timeout);
}
});
// add function to set the value directly
throttled['immediate'] = function(value) {
target(value);
};
return throttled;
};
然后使用它:
var waiting = ko.computed(function() {
return outstandingRequests() > 0;
}.extend({ throttleEx: 500 });
// These are called when AJAX requests begin or end
function ajaxBegin() {
outstandingRequests.immediate(++outstandingRequests());
}
function ajaxEnd() {
outstandingRequests.immediate(--outstandingRequests());
}
答案 1 :(得分:2)
您真正想要的是在waiting
true
notifySubscribers
观察时延迟通知。这可以通过拦截observable的var originalNotifySubscribers = this.isWaiting.notifySubscribers,
timeoutInstance;
this.isWaiting.notifySubscribers = function(value, event) {
clearTimeout(timeoutInstance);
if ((event === 'change' || event === undefined) && value) {
timeoutInstance = setTimeout(function() {
originalNotifySubscribers.call(this, value, event);
}.bind(this), 500);
} else {
originalNotifySubscribers.call(this, value, event);
}
};
函数来完成:
waiting
jsFiddle:http://jsfiddle.net/mbest/Pk6mH/
编辑:
我只想到了另一种可能更好的解决方案,针对您的具体案例。由于waiting
observable仅依赖于另一个observable,因此您可以创建一个更新var timeoutInstance;
this.isLoading.subscribe(function(value) {
clearTimeout(timeoutInstance);
if (value) {
timeoutInstance = setTimeout(function() {
this.isWaiting(true);
}.bind(this), 500);
} else {
this.isWaiting(false);
}
}, this);
可观察对象的手动订阅:
{{1}}
jsFiddle:http://jsfiddle.net/mbest/wCJHT/