Knockout.js 如何强制限制的可观察对象立即更新?

Knockout.js 如何强制限制的可观察对象立即更新?,knockout.js,computed-observable,Knockout.js,Computed Observable,我通过将“加载”指示器的可见性绑定到名为waiting的可观察指示器来显示或隐藏UI上的“加载”指示器,其定义如下: // Viewmodel var outstandingRequests = ko.observable(0); // true if any requests are outstanding var waiting = ko.computed(function() { return outstandingRequests() > 0; }.extend({ th

我通过将“加载”指示器的可见性绑定到名为
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>

如何绕过油门扩展并强制
等待
立即更新?

扩展可观察对象时,扩展器通常会将可观察对象与另一个具有所需行为的对象包装在一起。您可以保留对原始observable的引用,这将允许您对其进行直接写入,同时正常地公开受限制的observable版本

e、 g

在您的特定用例中,与其限制
等待
可观察的请求,不如限制
未处理的请求
可观察的请求,并在
等待
中使用限制值

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());
}
写入您的
未处理请求
可观察立即发生,但您的
等待
可观察将被有效抑制


或者,在我看来,一个更干净的解决方案是重新实现
节流
扩展器,以添加立即更新的能力

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());
}

您真正想要的是延迟
等待
的通知,当它变为
时可以观察到。这可以通过截取可观察对象的
notifySubscribers
功能来实现:

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);
    }
};
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);
jsFiddle:

编辑: 我只是想到了另一个,可能更好的,针对你的特殊情况的解决方案。由于
等待
可观察对象仅取决于另一个可观察对象,因此您可以创建手动订阅来更新
等待
可观察对象:

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);
    }
};
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);

jsFiddle:

Ah,所以
throttle
只是一个包装器,我明白了。但是我如何将我的UI绑定到多个可观察对象以获得所需的行为呢?为了最干净的实现,我可能会编写我自己的
throttle
extender实现来添加该功能,并在计算的可观察对象上使用它。或者,在您的特定情况下,您可以限制可观察的
未完成请求
而不是
等待
,并使用我的示例中的方法。考虑过您的情况后,我认为这不是理想的解决方案。尽管延迟,对
未决请求的任何更改
都将触发对
等待
的更新,因此快速更改不会将它们全部合并为一个更改。我将不得不重新思考这个问题。我并不是想把它们都集中到一个变化中去,而是我只想看到被限制的部分。换句话说,我需要一个
throttleUnlessNewValueIsZero
extender…仔细想想,我错了。回顾
节流的实现后
,对值的快速更改仍然只会发送一次更新。它的行为仍将大致相同。